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