xref: /aosp_15_r20/external/pigweed/pw_bluetooth_sapphire/peripheral.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker // Copyright 2024 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker //
3*61c4878aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker // the License at
6*61c4878aSAndroid Build Coastguard Worker //
7*61c4878aSAndroid Build Coastguard Worker //     https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker //
9*61c4878aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker // the License.
14*61c4878aSAndroid Build Coastguard Worker 
15*61c4878aSAndroid Build Coastguard Worker #include "pw_bluetooth_sapphire/peripheral.h"
16*61c4878aSAndroid Build Coastguard Worker 
17*61c4878aSAndroid Build Coastguard Worker namespace pw::bluetooth_sapphire {
18*61c4878aSAndroid Build Coastguard Worker 
19*61c4878aSAndroid Build Coastguard Worker static pw::sync::Mutex g_peripheral_lock;
20*61c4878aSAndroid Build Coastguard Worker 
21*61c4878aSAndroid Build Coastguard Worker using AdvertiseError = pw::bluetooth::low_energy::Peripheral2::AdvertiseError;
22*61c4878aSAndroid Build Coastguard Worker using LegacyAdvertising =
23*61c4878aSAndroid Build Coastguard Worker     pw::bluetooth::low_energy::Peripheral2::LegacyAdvertising;
24*61c4878aSAndroid Build Coastguard Worker using ExtendedAdvertising =
25*61c4878aSAndroid Build Coastguard Worker     pw::bluetooth::low_energy::Peripheral2::ExtendedAdvertising;
26*61c4878aSAndroid Build Coastguard Worker using ScanResponse = pw::bluetooth::low_energy::Peripheral2::ScanResponse;
27*61c4878aSAndroid Build Coastguard Worker using Anonymous =
28*61c4878aSAndroid Build Coastguard Worker     pw::bluetooth::low_energy::Peripheral2::ExtendedAdvertising::Anonymous;
29*61c4878aSAndroid Build Coastguard Worker using AdvertisedPeripheral2 = pw::bluetooth::low_energy::AdvertisedPeripheral2;
30*61c4878aSAndroid Build Coastguard Worker 
31*61c4878aSAndroid Build Coastguard Worker namespace {
UuidFrom(const pw::bluetooth::Uuid & uuid)32*61c4878aSAndroid Build Coastguard Worker bt::UUID UuidFrom(const pw::bluetooth::Uuid& uuid) {
33*61c4878aSAndroid Build Coastguard Worker   return bt::UUID(bt::BufferView(pw::as_bytes(uuid.As128BitSpan())));
34*61c4878aSAndroid Build Coastguard Worker }
35*61c4878aSAndroid Build Coastguard Worker 
AdvertisingDataFrom(const pw::bluetooth::low_energy::AdvertisingData & data_in)36*61c4878aSAndroid Build Coastguard Worker pw::expected<bt::AdvertisingData, AdvertiseError> AdvertisingDataFrom(
37*61c4878aSAndroid Build Coastguard Worker     const pw::bluetooth::low_energy::AdvertisingData& data_in) {
38*61c4878aSAndroid Build Coastguard Worker   bt::AdvertisingData data_out;
39*61c4878aSAndroid Build Coastguard Worker 
40*61c4878aSAndroid Build Coastguard Worker   if (!data_out.SetLocalName(std::string(data_in.name))) {
41*61c4878aSAndroid Build Coastguard Worker     return pw::unexpected(AdvertiseError::kAdvertisingDataTooLong);
42*61c4878aSAndroid Build Coastguard Worker   }
43*61c4878aSAndroid Build Coastguard Worker 
44*61c4878aSAndroid Build Coastguard Worker   data_out.SetAppearance(static_cast<uint16_t>(data_in.appearance));
45*61c4878aSAndroid Build Coastguard Worker 
46*61c4878aSAndroid Build Coastguard Worker   for (const bluetooth::Uuid& service_uuid : data_in.service_uuids) {
47*61c4878aSAndroid Build Coastguard Worker     if (!data_out.AddServiceUuid(UuidFrom(service_uuid))) {
48*61c4878aSAndroid Build Coastguard Worker       return pw::unexpected(AdvertiseError::kAdvertisingDataTooLong);
49*61c4878aSAndroid Build Coastguard Worker     }
50*61c4878aSAndroid Build Coastguard Worker   }
51*61c4878aSAndroid Build Coastguard Worker 
52*61c4878aSAndroid Build Coastguard Worker   for (const bluetooth::low_energy::ServiceData& service_data :
53*61c4878aSAndroid Build Coastguard Worker        data_in.service_data) {
54*61c4878aSAndroid Build Coastguard Worker     if (!data_out.SetServiceData(UuidFrom(service_data.uuid),
55*61c4878aSAndroid Build Coastguard Worker                                  bt::BufferView(service_data.data))) {
56*61c4878aSAndroid Build Coastguard Worker       return pw::unexpected(AdvertiseError::kAdvertisingDataTooLong);
57*61c4878aSAndroid Build Coastguard Worker     }
58*61c4878aSAndroid Build Coastguard Worker   }
59*61c4878aSAndroid Build Coastguard Worker 
60*61c4878aSAndroid Build Coastguard Worker   for (const bluetooth::low_energy::ManufacturerData& manufacturer_data :
61*61c4878aSAndroid Build Coastguard Worker        data_in.manufacturer_data) {
62*61c4878aSAndroid Build Coastguard Worker     if (!data_out.SetManufacturerData(manufacturer_data.company_id,
63*61c4878aSAndroid Build Coastguard Worker                                       bt::BufferView(manufacturer_data.data))) {
64*61c4878aSAndroid Build Coastguard Worker       return pw::unexpected(AdvertiseError::kAdvertisingDataTooLong);
65*61c4878aSAndroid Build Coastguard Worker     }
66*61c4878aSAndroid Build Coastguard Worker   }
67*61c4878aSAndroid Build Coastguard Worker 
68*61c4878aSAndroid Build Coastguard Worker   for (const std::string_view uri : data_in.uris) {
69*61c4878aSAndroid Build Coastguard Worker     if (!data_out.AddUri(std::string(uri))) {
70*61c4878aSAndroid Build Coastguard Worker       return pw::unexpected(AdvertiseError::kAdvertisingDataTooLong);
71*61c4878aSAndroid Build Coastguard Worker     }
72*61c4878aSAndroid Build Coastguard Worker   }
73*61c4878aSAndroid Build Coastguard Worker   return data_out;
74*61c4878aSAndroid Build Coastguard Worker }
75*61c4878aSAndroid Build Coastguard Worker 
DeviceAddressTypeFrom(pw::bluetooth::Address::Type address_type)76*61c4878aSAndroid Build Coastguard Worker bt::DeviceAddress::Type DeviceAddressTypeFrom(
77*61c4878aSAndroid Build Coastguard Worker     pw::bluetooth::Address::Type address_type) {
78*61c4878aSAndroid Build Coastguard Worker   // TODO: https://pwbug.dev/377301546 - Support all types of random addresses
79*61c4878aSAndroid Build Coastguard Worker   // in DeviceAddress::Type.
80*61c4878aSAndroid Build Coastguard Worker   switch (address_type) {
81*61c4878aSAndroid Build Coastguard Worker     case bluetooth::Address::Type::kPublic:
82*61c4878aSAndroid Build Coastguard Worker       return bt::DeviceAddress::Type::kLEPublic;
83*61c4878aSAndroid Build Coastguard Worker     case bluetooth::Address::Type::kRandomStatic:
84*61c4878aSAndroid Build Coastguard Worker       return bt::DeviceAddress::Type::kLERandom;
85*61c4878aSAndroid Build Coastguard Worker     case bluetooth::Address::Type::kRandomResolvablePrivate:
86*61c4878aSAndroid Build Coastguard Worker       return bt::DeviceAddress::Type::kLERandom;
87*61c4878aSAndroid Build Coastguard Worker     case bluetooth::Address::Type::kRandomNonResolvablePrivate:
88*61c4878aSAndroid Build Coastguard Worker       return bt::DeviceAddress::Type::kLERandom;
89*61c4878aSAndroid Build Coastguard Worker   }
90*61c4878aSAndroid Build Coastguard Worker }
91*61c4878aSAndroid Build Coastguard Worker 
BondableModeFrom(bool bondable)92*61c4878aSAndroid Build Coastguard Worker bt::sm::BondableMode BondableModeFrom(bool bondable) {
93*61c4878aSAndroid Build Coastguard Worker   return bondable ? bt::sm::BondableMode::Bondable
94*61c4878aSAndroid Build Coastguard Worker                   : bt::sm::BondableMode::NonBondable;
95*61c4878aSAndroid Build Coastguard Worker }
96*61c4878aSAndroid Build Coastguard Worker 
AdvertiseErrorFrom(bt::hci::Result<> result)97*61c4878aSAndroid Build Coastguard Worker AdvertiseError AdvertiseErrorFrom(bt::hci::Result<> result) {
98*61c4878aSAndroid Build Coastguard Worker   if (result.error_value().is(bt::HostError::kNotSupported)) {
99*61c4878aSAndroid Build Coastguard Worker     return AdvertiseError::kNotSupported;
100*61c4878aSAndroid Build Coastguard Worker   } else if (result.error_value().is(bt::HostError::kInvalidParameters)) {
101*61c4878aSAndroid Build Coastguard Worker     return AdvertiseError::kInvalidParameters;
102*61c4878aSAndroid Build Coastguard Worker   } else if (result.error_value().is(bt::HostError::kAdvertisingDataTooLong)) {
103*61c4878aSAndroid Build Coastguard Worker     return AdvertiseError::kAdvertisingDataTooLong;
104*61c4878aSAndroid Build Coastguard Worker   } else if (result.error_value().is(bt::HostError::kScanResponseTooLong)) {
105*61c4878aSAndroid Build Coastguard Worker     return AdvertiseError::kScanResponseDataTooLong;
106*61c4878aSAndroid Build Coastguard Worker   }
107*61c4878aSAndroid Build Coastguard Worker   return AdvertiseError::kFailed;
108*61c4878aSAndroid Build Coastguard Worker }
109*61c4878aSAndroid Build Coastguard Worker 
110*61c4878aSAndroid Build Coastguard Worker }  // namespace
111*61c4878aSAndroid Build Coastguard Worker 
Peripheral(bt::gap::Adapter::WeakPtr adapter,pw::async::Dispatcher & dispatcher)112*61c4878aSAndroid Build Coastguard Worker Peripheral::Peripheral(bt::gap::Adapter::WeakPtr adapter,
113*61c4878aSAndroid Build Coastguard Worker                        pw::async::Dispatcher& dispatcher)
114*61c4878aSAndroid Build Coastguard Worker     : dispatcher_(dispatcher), adapter_(std::move(adapter)) {}
115*61c4878aSAndroid Build Coastguard Worker 
~Peripheral()116*61c4878aSAndroid Build Coastguard Worker Peripheral::~Peripheral() {
117*61c4878aSAndroid Build Coastguard Worker   weak_factory_.InvalidatePtrs();
118*61c4878aSAndroid Build Coastguard Worker   {
119*61c4878aSAndroid Build Coastguard Worker     std::lock_guard guard(lock());
120*61c4878aSAndroid Build Coastguard Worker     for (auto& [_, adv] : advertisements_) {
121*61c4878aSAndroid Build Coastguard Worker       adv.OnStopLocked(pw::Status::Cancelled());
122*61c4878aSAndroid Build Coastguard Worker     }
123*61c4878aSAndroid Build Coastguard Worker     advertisements_.clear();
124*61c4878aSAndroid Build Coastguard Worker   }
125*61c4878aSAndroid Build Coastguard Worker }
126*61c4878aSAndroid Build Coastguard Worker 
Advertise(const AdvertisingParameters & parameters)127*61c4878aSAndroid Build Coastguard Worker async2::OnceReceiver<Peripheral::AdvertiseResult> Peripheral::Advertise(
128*61c4878aSAndroid Build Coastguard Worker     const AdvertisingParameters& parameters) {
129*61c4878aSAndroid Build Coastguard Worker   pw::expected<bt::AdvertisingData, AdvertiseError> data_result =
130*61c4878aSAndroid Build Coastguard Worker       AdvertisingDataFrom(parameters.data);
131*61c4878aSAndroid Build Coastguard Worker   if (!data_result.has_value()) {
132*61c4878aSAndroid Build Coastguard Worker     return async2::OnceReceiver<Peripheral::AdvertiseResult>(
133*61c4878aSAndroid Build Coastguard Worker         pw::unexpected(data_result.error()));
134*61c4878aSAndroid Build Coastguard Worker   }
135*61c4878aSAndroid Build Coastguard Worker   bt::AdvertisingData data = std::move(data_result.value());
136*61c4878aSAndroid Build Coastguard Worker   bt::AdvertisingData scan_response;
137*61c4878aSAndroid Build Coastguard Worker   bool include_tx_power_level = parameters.data.include_tx_power_level;
138*61c4878aSAndroid Build Coastguard Worker 
139*61c4878aSAndroid Build Coastguard Worker   // TODO: https://pwbug.dev/377301546 - Use parameters.interval_range & update
140*61c4878aSAndroid Build Coastguard Worker   // internal API to accept a range instead of AdvertisingInterval.
141*61c4878aSAndroid Build Coastguard Worker   bt::gap::AdvertisingInterval interval = bt::gap::AdvertisingInterval::SLOW;
142*61c4878aSAndroid Build Coastguard Worker 
143*61c4878aSAndroid Build Coastguard Worker   std::optional<bt::gap::Adapter::LowEnergy::ConnectableAdvertisingParameters>
144*61c4878aSAndroid Build Coastguard Worker       connectable;
145*61c4878aSAndroid Build Coastguard Worker 
146*61c4878aSAndroid Build Coastguard Worker   auto connection_cb =
147*61c4878aSAndroid Build Coastguard Worker       [self = self_](bt::gap::AdvertisementId advertisement_id,
148*61c4878aSAndroid Build Coastguard Worker                      bt::gap::Adapter::LowEnergy::ConnectionResult result) {
149*61c4878aSAndroid Build Coastguard Worker         if (self.is_alive()) {
150*61c4878aSAndroid Build Coastguard Worker           self->OnConnection(advertisement_id, std::move(result));
151*61c4878aSAndroid Build Coastguard Worker         }
152*61c4878aSAndroid Build Coastguard Worker       };
153*61c4878aSAndroid Build Coastguard Worker 
154*61c4878aSAndroid Build Coastguard Worker   std::optional<bt::DeviceAddress::Type> address_type;
155*61c4878aSAndroid Build Coastguard Worker   if (parameters.address_type.has_value()) {
156*61c4878aSAndroid Build Coastguard Worker     address_type = DeviceAddressTypeFrom(parameters.address_type.value());
157*61c4878aSAndroid Build Coastguard Worker   }
158*61c4878aSAndroid Build Coastguard Worker 
159*61c4878aSAndroid Build Coastguard Worker   bool anonymous = false;
160*61c4878aSAndroid Build Coastguard Worker   bool extended_pdu = false;
161*61c4878aSAndroid Build Coastguard Worker 
162*61c4878aSAndroid Build Coastguard Worker   if (const LegacyAdvertising* legacy =
163*61c4878aSAndroid Build Coastguard Worker           std::get_if<LegacyAdvertising>(&parameters.procedure)) {
164*61c4878aSAndroid Build Coastguard Worker     if (legacy->scan_response.has_value()) {
165*61c4878aSAndroid Build Coastguard Worker       pw::expected<bt::AdvertisingData, AdvertiseError> scan_response_result =
166*61c4878aSAndroid Build Coastguard Worker           AdvertisingDataFrom(legacy->scan_response.value());
167*61c4878aSAndroid Build Coastguard Worker       if (!scan_response_result.has_value()) {
168*61c4878aSAndroid Build Coastguard Worker         return async2::OnceReceiver<Peripheral::AdvertiseResult>(
169*61c4878aSAndroid Build Coastguard Worker             pw::unexpected(scan_response_result.error()));
170*61c4878aSAndroid Build Coastguard Worker       }
171*61c4878aSAndroid Build Coastguard Worker       scan_response = std::move(scan_response_result.value());
172*61c4878aSAndroid Build Coastguard Worker     }
173*61c4878aSAndroid Build Coastguard Worker 
174*61c4878aSAndroid Build Coastguard Worker     if (legacy->connection_options.has_value()) {
175*61c4878aSAndroid Build Coastguard Worker       connectable.emplace();
176*61c4878aSAndroid Build Coastguard Worker       connectable->connection_cb = std::move(connection_cb);
177*61c4878aSAndroid Build Coastguard Worker       connectable->bondable_mode =
178*61c4878aSAndroid Build Coastguard Worker           BondableModeFrom(legacy->connection_options->bondable_mode);
179*61c4878aSAndroid Build Coastguard Worker 
180*61c4878aSAndroid Build Coastguard Worker       // TODO: https://pwbug.dev/377301546 - Use remaining connection options.
181*61c4878aSAndroid Build Coastguard Worker       // Requires modifying Adapter::LowEnergy::StartAdvertising.
182*61c4878aSAndroid Build Coastguard Worker     }
183*61c4878aSAndroid Build Coastguard Worker   } else if (const ExtendedAdvertising* extended =
184*61c4878aSAndroid Build Coastguard Worker                  std::get_if<ExtendedAdvertising>(&parameters.procedure)) {
185*61c4878aSAndroid Build Coastguard Worker     extended_pdu = true;
186*61c4878aSAndroid Build Coastguard Worker 
187*61c4878aSAndroid Build Coastguard Worker     if (std::get_if<Anonymous>(&extended->configuration)) {
188*61c4878aSAndroid Build Coastguard Worker       anonymous = true;
189*61c4878aSAndroid Build Coastguard Worker     } else if (const ScanResponse* scan_response_param =
190*61c4878aSAndroid Build Coastguard Worker                    std::get_if<ScanResponse>(&extended->configuration)) {
191*61c4878aSAndroid Build Coastguard Worker       pw::expected<bt::AdvertisingData, AdvertiseError> scan_response_result =
192*61c4878aSAndroid Build Coastguard Worker           AdvertisingDataFrom(*scan_response_param);
193*61c4878aSAndroid Build Coastguard Worker       if (!scan_response_result.has_value()) {
194*61c4878aSAndroid Build Coastguard Worker         return async2::OnceReceiver<Peripheral::AdvertiseResult>(
195*61c4878aSAndroid Build Coastguard Worker             pw::unexpected(scan_response_result.error()));
196*61c4878aSAndroid Build Coastguard Worker       }
197*61c4878aSAndroid Build Coastguard Worker       scan_response = std::move(scan_response_result.value());
198*61c4878aSAndroid Build Coastguard Worker     } else if (const ConnectionOptions* connection_options =
199*61c4878aSAndroid Build Coastguard Worker                    std::get_if<ConnectionOptions>(&extended->configuration)) {
200*61c4878aSAndroid Build Coastguard Worker       connectable.emplace();
201*61c4878aSAndroid Build Coastguard Worker       connectable->connection_cb = std::move(connection_cb);
202*61c4878aSAndroid Build Coastguard Worker       connectable->bondable_mode =
203*61c4878aSAndroid Build Coastguard Worker           BondableModeFrom(connection_options->bondable_mode);
204*61c4878aSAndroid Build Coastguard Worker 
205*61c4878aSAndroid Build Coastguard Worker       // TODO: https://pwbug.dev/377301546 - Use remaining connection options.
206*61c4878aSAndroid Build Coastguard Worker       // Requires modifying Adapter::LowEnergy::StartAdvertising.
207*61c4878aSAndroid Build Coastguard Worker     }
208*61c4878aSAndroid Build Coastguard Worker   } else {
209*61c4878aSAndroid Build Coastguard Worker     // This should never happen unless additional procedures are added in the
210*61c4878aSAndroid Build Coastguard Worker     // future.
211*61c4878aSAndroid Build Coastguard Worker     bt_log(WARN, "api", "Advertising procedure not supported");
212*61c4878aSAndroid Build Coastguard Worker     return async2::OnceReceiver<Peripheral::AdvertiseResult>(
213*61c4878aSAndroid Build Coastguard Worker         pw::unexpected(AdvertiseError::kNotSupported));
214*61c4878aSAndroid Build Coastguard Worker   }
215*61c4878aSAndroid Build Coastguard Worker 
216*61c4878aSAndroid Build Coastguard Worker   auto [result_sender, result_receiver] =
217*61c4878aSAndroid Build Coastguard Worker       async2::MakeOnceSenderAndReceiver<Peripheral::AdvertiseResult>();
218*61c4878aSAndroid Build Coastguard Worker   auto callback = [self = self_, sender = std::move(result_sender)](
219*61c4878aSAndroid Build Coastguard Worker                       bt::gap::AdvertisementInstance instance,
220*61c4878aSAndroid Build Coastguard Worker                       bt::hci::Result<> status) mutable {
221*61c4878aSAndroid Build Coastguard Worker     if (self.is_alive()) {
222*61c4878aSAndroid Build Coastguard Worker       self->OnAdvertiseResult(std::move(instance), status, std::move(sender));
223*61c4878aSAndroid Build Coastguard Worker     }
224*61c4878aSAndroid Build Coastguard Worker   };
225*61c4878aSAndroid Build Coastguard Worker 
226*61c4878aSAndroid Build Coastguard Worker   // Post to BT dispatcher for thread safety.
227*61c4878aSAndroid Build Coastguard Worker   pw::Status post_status =
228*61c4878aSAndroid Build Coastguard Worker       dispatcher_.Post([adapter = adapter_,
229*61c4878aSAndroid Build Coastguard Worker                         adv_data = std::move(data),
230*61c4878aSAndroid Build Coastguard Worker                         scan_rsp = std::move(scan_response),
231*61c4878aSAndroid Build Coastguard Worker                         interval,
232*61c4878aSAndroid Build Coastguard Worker                         extended_pdu,
233*61c4878aSAndroid Build Coastguard Worker                         anonymous,
234*61c4878aSAndroid Build Coastguard Worker                         include_tx_power_level,
235*61c4878aSAndroid Build Coastguard Worker                         connection_options = std::move(connectable),
236*61c4878aSAndroid Build Coastguard Worker                         address_type,
237*61c4878aSAndroid Build Coastguard Worker                         cb = std::move(callback)](pw::async::Context&,
238*61c4878aSAndroid Build Coastguard Worker                                                   pw::Status status) mutable {
239*61c4878aSAndroid Build Coastguard Worker         if (!status.ok()) {
240*61c4878aSAndroid Build Coastguard Worker           // Dispatcher is shutting down.
241*61c4878aSAndroid Build Coastguard Worker           return;
242*61c4878aSAndroid Build Coastguard Worker         }
243*61c4878aSAndroid Build Coastguard Worker         adapter->le()->StartAdvertising(std::move(adv_data),
244*61c4878aSAndroid Build Coastguard Worker                                         std::move(scan_rsp),
245*61c4878aSAndroid Build Coastguard Worker                                         interval,
246*61c4878aSAndroid Build Coastguard Worker                                         extended_pdu,
247*61c4878aSAndroid Build Coastguard Worker                                         anonymous,
248*61c4878aSAndroid Build Coastguard Worker                                         include_tx_power_level,
249*61c4878aSAndroid Build Coastguard Worker                                         std::move(connection_options),
250*61c4878aSAndroid Build Coastguard Worker                                         address_type,
251*61c4878aSAndroid Build Coastguard Worker                                         std::move(cb));
252*61c4878aSAndroid Build Coastguard Worker       });
253*61c4878aSAndroid Build Coastguard Worker   PW_CHECK_OK(post_status);
254*61c4878aSAndroid Build Coastguard Worker 
255*61c4878aSAndroid Build Coastguard Worker   return std::move(result_receiver);
256*61c4878aSAndroid Build Coastguard Worker }
257*61c4878aSAndroid Build Coastguard Worker 
lock()258*61c4878aSAndroid Build Coastguard Worker pw::sync::Mutex& Peripheral::lock() { return g_peripheral_lock; }
259*61c4878aSAndroid Build Coastguard Worker 
StopAdvertising()260*61c4878aSAndroid Build Coastguard Worker void Peripheral::AdvertisedPeripheralImpl::StopAdvertising() {
261*61c4878aSAndroid Build Coastguard Worker   std::lock_guard guard(Peripheral::lock());
262*61c4878aSAndroid Build Coastguard Worker   if (!peripheral_) {
263*61c4878aSAndroid Build Coastguard Worker     return;
264*61c4878aSAndroid Build Coastguard Worker   }
265*61c4878aSAndroid Build Coastguard Worker 
266*61c4878aSAndroid Build Coastguard Worker   peripheral_->StopAdvertising(id_);
267*61c4878aSAndroid Build Coastguard Worker }
268*61c4878aSAndroid Build Coastguard Worker 
PendStop(async2::Context & cx)269*61c4878aSAndroid Build Coastguard Worker async2::Poll<pw::Status> Peripheral::AdvertisedPeripheralImpl::PendStop(
270*61c4878aSAndroid Build Coastguard Worker     async2::Context& cx) {
271*61c4878aSAndroid Build Coastguard Worker   std::lock_guard guard(Peripheral::lock());
272*61c4878aSAndroid Build Coastguard Worker   if (stop_status_.has_value()) {
273*61c4878aSAndroid Build Coastguard Worker     return async2::Ready(stop_status_.value());
274*61c4878aSAndroid Build Coastguard Worker   }
275*61c4878aSAndroid Build Coastguard Worker   PW_ASYNC_STORE_WAKER(cx, waker_, "AdvPeripheralPendStop");
276*61c4878aSAndroid Build Coastguard Worker   return async2::Pending();
277*61c4878aSAndroid Build Coastguard Worker }
278*61c4878aSAndroid Build Coastguard Worker 
~Advertisement()279*61c4878aSAndroid Build Coastguard Worker Peripheral::Advertisement::~Advertisement() { OnStopLocked(OkStatus()); }
280*61c4878aSAndroid Build Coastguard Worker 
OnStopLocked(pw::Status status)281*61c4878aSAndroid Build Coastguard Worker void Peripheral::Advertisement::OnStopLocked(pw::Status status) {
282*61c4878aSAndroid Build Coastguard Worker   if (!advertised_peripheral_) {
283*61c4878aSAndroid Build Coastguard Worker     return;
284*61c4878aSAndroid Build Coastguard Worker   }
285*61c4878aSAndroid Build Coastguard Worker 
286*61c4878aSAndroid Build Coastguard Worker   advertised_peripheral_->stop_status_ = status;
287*61c4878aSAndroid Build Coastguard Worker   advertised_peripheral_->peripheral_ = nullptr;
288*61c4878aSAndroid Build Coastguard Worker   std::move(advertised_peripheral_->waker_).Wake();
289*61c4878aSAndroid Build Coastguard Worker   advertised_peripheral_ = nullptr;
290*61c4878aSAndroid Build Coastguard Worker }
291*61c4878aSAndroid Build Coastguard Worker 
OnAdvertisedPeripheralDestroyedLocked(bt::gap::AdvertisementId advertisement_id)292*61c4878aSAndroid Build Coastguard Worker void Peripheral::OnAdvertisedPeripheralDestroyedLocked(
293*61c4878aSAndroid Build Coastguard Worker     bt::gap::AdvertisementId advertisement_id) {
294*61c4878aSAndroid Build Coastguard Worker   auto iter = advertisements_.find(advertisement_id);
295*61c4878aSAndroid Build Coastguard Worker   if (iter == advertisements_.end()) {
296*61c4878aSAndroid Build Coastguard Worker     return;
297*61c4878aSAndroid Build Coastguard Worker   }
298*61c4878aSAndroid Build Coastguard Worker   iter->second.OnAdvertisedPeripheralDestroyedLocked();
299*61c4878aSAndroid Build Coastguard Worker   StopAdvertising(advertisement_id);
300*61c4878aSAndroid Build Coastguard Worker }
301*61c4878aSAndroid Build Coastguard Worker 
StopAdvertising(bt::gap::AdvertisementId advertisement_id)302*61c4878aSAndroid Build Coastguard Worker void Peripheral::StopAdvertising(bt::gap::AdvertisementId advertisement_id) {
303*61c4878aSAndroid Build Coastguard Worker   // Post to BT dispatcher for thread safety.
304*61c4878aSAndroid Build Coastguard Worker   pw::Status post_status =
305*61c4878aSAndroid Build Coastguard Worker       dispatcher_.Post([self = self_, id = advertisement_id](
306*61c4878aSAndroid Build Coastguard Worker                            pw::async::Context&, pw::Status status) {
307*61c4878aSAndroid Build Coastguard Worker         if (!self.is_alive() || !status.ok()) {
308*61c4878aSAndroid Build Coastguard Worker           return;
309*61c4878aSAndroid Build Coastguard Worker         }
310*61c4878aSAndroid Build Coastguard Worker         std::lock_guard guard(Peripheral::lock());
311*61c4878aSAndroid Build Coastguard Worker         // TODO: https://pwbug.dev/377301546 - Implement a callback for when
312*61c4878aSAndroid Build Coastguard Worker         // advertising is actually stopped. This just destroys the
313*61c4878aSAndroid Build Coastguard Worker         // AdvertisementInstance and does not wait for advertising to actually
314*61c4878aSAndroid Build Coastguard Worker         // stop, so it does not properly implement
315*61c4878aSAndroid Build Coastguard Worker         // AdvertisedPeripheral2::StopAdvertising().
316*61c4878aSAndroid Build Coastguard Worker         self->advertisements_.erase(id);
317*61c4878aSAndroid Build Coastguard Worker       });
318*61c4878aSAndroid Build Coastguard Worker   PW_CHECK_OK(post_status);
319*61c4878aSAndroid Build Coastguard Worker }
320*61c4878aSAndroid Build Coastguard Worker 
OnAdvertiseResult(bt::gap::AdvertisementInstance instance,bt::hci::Result<> result,async2::OnceSender<AdvertiseResult> result_sender)321*61c4878aSAndroid Build Coastguard Worker void Peripheral::OnAdvertiseResult(
322*61c4878aSAndroid Build Coastguard Worker     bt::gap::AdvertisementInstance instance,
323*61c4878aSAndroid Build Coastguard Worker     bt::hci::Result<> result,
324*61c4878aSAndroid Build Coastguard Worker     async2::OnceSender<AdvertiseResult> result_sender) {
325*61c4878aSAndroid Build Coastguard Worker   if (result.is_error()) {
326*61c4878aSAndroid Build Coastguard Worker     result_sender.emplace(pw::unexpected(AdvertiseErrorFrom(result)));
327*61c4878aSAndroid Build Coastguard Worker     return;
328*61c4878aSAndroid Build Coastguard Worker   }
329*61c4878aSAndroid Build Coastguard Worker 
330*61c4878aSAndroid Build Coastguard Worker   bt::gap::AdvertisementId id = instance.id();
331*61c4878aSAndroid Build Coastguard Worker 
332*61c4878aSAndroid Build Coastguard Worker   AdvertisedPeripheralImpl* impl = new AdvertisedPeripheralImpl(id, this);
333*61c4878aSAndroid Build Coastguard Worker   AdvertisedPeripheral2::Ptr advertised_peripheral(impl);
334*61c4878aSAndroid Build Coastguard Worker 
335*61c4878aSAndroid Build Coastguard Worker   std::lock_guard guard(lock());
336*61c4878aSAndroid Build Coastguard Worker   auto [iter, inserted] =
337*61c4878aSAndroid Build Coastguard Worker       advertisements_.try_emplace(id, std::move(instance), impl);
338*61c4878aSAndroid Build Coastguard Worker   PW_CHECK(inserted);
339*61c4878aSAndroid Build Coastguard Worker 
340*61c4878aSAndroid Build Coastguard Worker   result_sender.emplace(std::move(advertised_peripheral));
341*61c4878aSAndroid Build Coastguard Worker }
342*61c4878aSAndroid Build Coastguard Worker 
OnConnection(bt::gap::AdvertisementId,bt::gap::Adapter::LowEnergy::ConnectionResult)343*61c4878aSAndroid Build Coastguard Worker void Peripheral::OnConnection(
344*61c4878aSAndroid Build Coastguard Worker     bt::gap::AdvertisementId /*advertisement_id*/,
345*61c4878aSAndroid Build Coastguard Worker     bt::gap::Adapter::LowEnergy::ConnectionResult /*result*/) {
346*61c4878aSAndroid Build Coastguard Worker   // TODO: https://pwbug.dev/377301546 - Implement connection handling.
347*61c4878aSAndroid Build Coastguard Worker }
348*61c4878aSAndroid Build Coastguard Worker 
349*61c4878aSAndroid Build Coastguard Worker }  // namespace pw::bluetooth_sapphire
350