xref: /aosp_15_r20/external/pigweed/pw_bluetooth_sapphire/public/pw_bluetooth_sapphire/peripheral.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2024 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 
17 #include "pw_bluetooth/low_energy/peripheral2.h"
18 #include "pw_bluetooth_sapphire/internal/host/gap/adapter.h"
19 
20 namespace pw::bluetooth_sapphire {
21 
22 /// Must only be constructed and destroyed on the Bluetooth thread.
23 class Peripheral final : public pw::bluetooth::low_energy::Peripheral2 {
24  public:
25   // TODO: https://pwbug.dev/377301546 - Don't expose Adapter in public API.
26   /// Must only be constructed on the Bluetooth thread.
27   Peripheral(bt::gap::Adapter::WeakPtr adapter,
28              pw::async::Dispatcher& dispatcher);
29 
30   /// Must only be destroyed on the Bluetooth thread.
31   ~Peripheral() override;
32 
33   /// Thread safe.
34   /// The AdvertisedPeripheral2 returned on success is thread safe.
35   async2::OnceReceiver<AdvertiseResult> Advertise(
36       const AdvertisingParameters& parameters) override
37       PW_LOCKS_EXCLUDED(lock());
38 
39   static pw::sync::Mutex& lock();
40 
41  private:
42   class Advertisement;
43 
44   // Thin client handle for an active advertisement.
45   // Thread safe.
46   class AdvertisedPeripheralImpl final
47       : public pw::bluetooth::low_energy::AdvertisedPeripheral2 {
48    public:
AdvertisedPeripheralImpl(bt::gap::AdvertisementId id,Peripheral * peripheral)49     AdvertisedPeripheralImpl(bt::gap::AdvertisementId id,
50                              Peripheral* peripheral)
51         : id_(id), peripheral_(peripheral) {}
~AdvertisedPeripheralImpl()52     ~AdvertisedPeripheralImpl() override {
53       std::lock_guard lock(Peripheral::lock());
54       if (peripheral_) {
55         peripheral_->OnAdvertisedPeripheralDestroyedLocked(id_);
56       }
57     }
58 
59     // AdvertisedPeripheral2 overrides:
PendConnection(async2::Context & cx)60     async2::Poll<pw::bluetooth::low_energy::Connection2::Ptr> PendConnection(
61         async2::Context& cx) override {
62       // TODO: https://pwbug.dev/377301546 - Implement connection handling.
63       return async2::Pending();
64     }
65     void StopAdvertising() override;
66     async2::Poll<pw::Status> PendStop(async2::Context& cx) override;
Release()67     void Release() override { delete this; }
68 
69    private:
70     friend class Advertisement;
71 
72     const bt::gap::AdvertisementId id_;
73 
74     // Set to null if the advertisement is stopped or Peripheral is destroyed.
75     Peripheral* peripheral_ PW_GUARDED_BY(lock());
76 
77     std::optional<pw::Status> stop_status_ PW_GUARDED_BY(lock());
78 
79     // Waker shared by PendConnection() and PendStop().
80     async2::Waker waker_ PW_GUARDED_BY(lock());
81   };
82 
83   // Active advertisement state. Must only be destroyed on the Bluetooth thread.
84   class Advertisement final {
85    public:
Advertisement(bt::gap::AdvertisementInstance && instance,AdvertisedPeripheralImpl * advertised_peripheral)86     Advertisement(bt::gap::AdvertisementInstance&& instance,
87                   AdvertisedPeripheralImpl* advertised_peripheral)
88         : advertised_peripheral_(advertised_peripheral),
89           instance_(std::move(instance)) {}
90 
91     // Must only be destroyed on Bluetooth thread.
92     ~Advertisement();
93 
OnAdvertisedPeripheralDestroyedLocked()94     void OnAdvertisedPeripheralDestroyedLocked()
95         PW_EXCLUSIVE_LOCKS_REQUIRED(lock()) {
96       advertised_peripheral_ = nullptr;
97     }
98 
99     void OnStopLocked(pw::Status status) PW_EXCLUSIVE_LOCKS_REQUIRED(lock());
100 
101    private:
102     friend class AdvertisedPeripheralImpl;
103 
104     AdvertisedPeripheralImpl* advertised_peripheral_;
105 
106     // Must only be modified/destroyed on the Bluetooth thread.
107     bt::gap::AdvertisementInstance instance_;
108   };
109 
110   // Thread safe.
111   void OnAdvertisedPeripheralDestroyedLocked(
112       bt::gap::AdvertisementId advertisement_id)
113       PW_EXCLUSIVE_LOCKS_REQUIRED(lock());
114 
115   // Thread safe. The lock may be held when calling this function as the stop
116   // message is immediately posted to the Bluetooth thread.
117   void StopAdvertising(bt::gap::AdvertisementId advertisement_id);
118 
119   // Always called on Bluetooth thread.
120   void OnAdvertiseResult(bt::gap::AdvertisementInstance instance,
121                          bt::hci::Result<> result,
122                          async2::OnceSender<AdvertiseResult> result_sender);
123 
124   // Always called on Bluetooth thread.
125   void OnConnection(bt::gap::AdvertisementId advertisement_id,
126                     bt::gap::Adapter::LowEnergy::ConnectionResult result);
127 
128   // Dispatcher for Bluetooth thread. Thread safe.
129   pw::async::HeapDispatcher dispatcher_;
130 
131   // Must only be used on the Bluetooth thread.
132   bt::gap::Adapter::WeakPtr adapter_;
133 
134   std::unordered_map<bt::gap::AdvertisementId, Advertisement> advertisements_
135       PW_GUARDED_BY(lock());
136 
137   // Must only be used on the Bluetooth thread.
138   WeakSelf<Peripheral> weak_factory_{this};
139 
140   // Thread safe to copy and destroy, but WeakPtr should only be used
141   // or dereferenced on the Bluetooth thread (WeakRef is not thread safe).
142   WeakSelf<Peripheral>::WeakPtr self_{weak_factory_.GetWeakPtr()};
143 };
144 
145 }  // namespace pw::bluetooth_sapphire
146