• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/central2.h"
18 #include "pw_bluetooth_sapphire/internal/connection.h"
19 #include "pw_bluetooth_sapphire/internal/host/gap/adapter.h"
20 #include "pw_multibuf/allocator.h"
21 
22 namespace pw::bluetooth_sapphire {
23 
24 /// Must only be constructed and destroyed on the Bluetooth thread.
25 class Central final : public pw::bluetooth::low_energy::Central2 {
26  public:
27   // The maximum number of scan results to queue in each ScanHandle
28   static constexpr uint8_t kMaxScanResultsQueueSize = 10;
29 
30   // TODO: https://pwbug.dev/377301546 - Don't expose Adapter in public API.
31   /// Must only be constructed on the Bluetooth thread.
32   /// @param allocator The allocator to use for advertising data buffers.
33   Central(bt::gap::Adapter::WeakPtr adapter,
34           pw::async::Dispatcher& dispatcher,
35           pw::multibuf::MultiBufAllocator& allocator);
36   ~Central() override;
37 
38   async2::OnceReceiver<ConnectResult> Connect(
39       pw::bluetooth::PeerId peer_id,
40       bluetooth::low_energy::Connection2::ConnectionOptions options) override
41       PW_LOCKS_EXCLUDED(lock());
42 
43   async2::OnceReceiver<ScanStartResult> Scan(
44       const ScanOptions& options) override PW_LOCKS_EXCLUDED(lock());
45 
46   static pw::sync::Mutex& lock();
47 
48  private:
49   class ScanHandleImpl final : public ScanHandle {
50    public:
ScanHandleImpl(uint16_t scan_id,Central * central)51     explicit ScanHandleImpl(uint16_t scan_id, Central* central)
52         : scan_id_(scan_id), central_(central) {}
53 
54     // Synchronously clears ScanState's pointer to this object and
55     // asynchronously stops the scan procedure.
56     ~ScanHandleImpl() override;
57 
58     void QueueScanResultLocked(ScanResult&& result)
59         PW_EXCLUSIVE_LOCKS_REQUIRED(lock());
60 
WakeLocked()61     void WakeLocked() PW_EXCLUSIVE_LOCKS_REQUIRED(lock()) {
62       std::move(waker_).Wake();
63     }
64 
OnScanErrorLocked()65     void OnScanErrorLocked() PW_EXCLUSIVE_LOCKS_REQUIRED(lock()) {
66       central_ = nullptr;
67       WakeLocked();
68     }
69 
70    private:
71     async2::Poll<pw::Result<ScanResult>> PendResult(
72         async2::Context& cx) override;
73 
74     // std::unique_ptr custom Deleter
Release()75     void Release() override { delete this; }
76 
77     const uint16_t scan_id_;
78 
79     // Set to null when Central is destroyed or scanning has stopped.
80     Central* central_ PW_GUARDED_BY(lock());
81 
82     // PendResult() waker. Set when Pending was returned.
83     async2::Waker waker_ PW_GUARDED_BY(lock());
84     std::queue<ScanResult> results_ PW_GUARDED_BY(lock());
85   };
86 
87   // Created and destroyed on the Bluetooth thread.
88   class ScanState {
89    public:
90     // Must be run on Bluetooth thread. Not thread safe.
91     explicit ScanState(
92         std::unique_ptr<bt::gap::LowEnergyDiscoverySession> session,
93         ScanHandleImpl* scan_handle,
94         uint16_t scan_id,
95         Central* central);
96 
97     ~ScanState();
98 
OnScanHandleDestroyedLocked()99     void OnScanHandleDestroyedLocked() PW_EXCLUSIVE_LOCKS_REQUIRED(lock()) {
100       scan_handle_ = nullptr;
101     }
102 
103    private:
104     // Must be run on Bluetooth thread. Not thread safe.
105     void OnScanResult(const bt::gap::Peer& peer) PW_LOCKS_EXCLUDED(lock());
106 
107     // Must be run on Bluetooth thread. Not thread safe.
108     void OnError() PW_LOCKS_EXCLUDED(lock());
109 
110     const uint16_t scan_id_;
111 
112     // Set to null synchronously when ScanHandleImpl is destroyed.
113     ScanHandleImpl* scan_handle_ PW_GUARDED_BY(lock());
114 
115     // Members must only be accessed on Bluetooth thread.
116     Central* const central_;
117     std::unique_ptr<bt::gap::LowEnergyDiscoverySession> session_;
118   };
119 
120   // Asynchronously stops the scan corresponding to `scan_id` and synchronously
121   // clears `ScanState.scan_handle_`.
122   void StopScanLocked(uint16_t scan_id) PW_EXCLUSIVE_LOCKS_REQUIRED(lock());
123 
124   void OnConnectionResult(bt::PeerId peer_id,
125                           bt::gap::Adapter::LowEnergy::ConnectionResult result,
126                           async2::OnceSender<ConnectResult> result_sender)
127       PW_LOCKS_EXCLUDED(lock());
128 
129   std::unordered_map<uint16_t, ScanState> scans_ PW_GUARDED_BY(lock());
130 
131   // Must only be used on the Bluetooth thread.
132   bt::gap::Adapter::WeakPtr adapter_;
133 
134   // Dispatcher for Bluetooth thread. Thread safe.
135   pw::async::Dispatcher& dispatcher_;
136   pw::async::HeapDispatcher heap_dispatcher_;
137 
138   pw::multibuf::MultiBufAllocator& allocator_;
139 
140   // Must only be used on the Bluetooth thread.
141   WeakSelf<Central> weak_factory_{this};
142 
143   // Thread safe to copy and destroy, but WeakPtr should only be used
144   // or dereferenced on the Bluetooth thread (WeakRef is not thread safe).
145   WeakSelf<Central>::WeakPtr self_{weak_factory_.GetWeakPtr()};
146 };
147 
148 }  // namespace pw::bluetooth_sapphire
149