xref: /aosp_15_r20/external/pigweed/pw_bluetooth_sapphire/host/gap/bredr_connection_request.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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 #include "pw_bluetooth_sapphire/internal/host/gap/bredr_connection_request.h"
16 
17 namespace bt::gap {
18 
19 namespace {
20 
21 const char* const kInspectHasIncomingPropertyName = "has_incoming";
22 const char* const kInspectCallbacksPropertyName = "callbacks";
23 const char* const kInspectFirstCreateConnectionReqMadeName =
24     "first_create_connection_request_timestamp";
25 const char* const kInspectPeerIdPropertyName = "peer_id";
26 constexpr pw::chrono::SystemClock::duration kRetryWindowAfterFirstCreateConn =
27     std::chrono::seconds(30);
28 
29 }  // namespace
30 
BrEdrConnectionRequest(pw::async::Dispatcher & pw_dispatcher,const DeviceAddress & addr,PeerId peer_id,Peer::InitializingConnectionToken token)31 BrEdrConnectionRequest::BrEdrConnectionRequest(
32     pw::async::Dispatcher& pw_dispatcher,
33     const DeviceAddress& addr,
34     PeerId peer_id,
35     Peer::InitializingConnectionToken token)
36     : peer_id_(peer_id),
37       address_(addr),
38       callbacks_(/*convert=*/[](auto& c) { return c.size(); }),
39       peer_init_conn_token_(std::move(token)),
40       dispatcher_(pw_dispatcher) {}
41 
BrEdrConnectionRequest(pw::async::Dispatcher & pw_dispatcher,const DeviceAddress & addr,PeerId peer_id,Peer::InitializingConnectionToken token,OnComplete && callback)42 BrEdrConnectionRequest::BrEdrConnectionRequest(
43     pw::async::Dispatcher& pw_dispatcher,
44     const DeviceAddress& addr,
45     PeerId peer_id,
46     Peer::InitializingConnectionToken token,
47     OnComplete&& callback)
48     : BrEdrConnectionRequest(pw_dispatcher, addr, peer_id, std::move(token)) {
49   callbacks_.Mutable()->push_back(std::move(callback));
50 }
51 
NotifyCallbacks(hci::Result<> status,const RefFactory & generate_ref)52 void BrEdrConnectionRequest::NotifyCallbacks(hci::Result<> status,
53                                              const RefFactory& generate_ref) {
54   // Clear token before notifying callbacks so that connection state change is
55   // reflected in callbacks.
56   peer_init_conn_token_.reset();
57 
58   // If this request has been moved from, |callbacks_| may be empty.
59   for (const auto& callback : *callbacks_) {
60     callback(status, generate_ref());
61   }
62 }
63 
AttachInspect(inspect::Node & parent,std::string name)64 void BrEdrConnectionRequest::AttachInspect(inspect::Node& parent,
65                                            std::string name) {
66   inspect_node_ = parent.CreateChild(name);
67   has_incoming_.AttachInspect(inspect_node_, kInspectHasIncomingPropertyName);
68   callbacks_.AttachInspect(inspect_node_, kInspectCallbacksPropertyName);
69   first_create_connection_req_made_.AttachInspect(
70       inspect_node_, kInspectFirstCreateConnectionReqMadeName);
71   peer_id_property_ = inspect_node_.CreateString(kInspectPeerIdPropertyName,
72                                                  peer_id_.ToString());
73 }
74 
75 std::unique_ptr<hci::BrEdrConnectionRequest>
CreateHciConnectionRequest(hci::CommandChannel * command_channel,std::optional<uint16_t> clock_offset,std::optional<pw::bluetooth::emboss::PageScanRepetitionMode> page_scan_repetition_mode,OnTimeout timeout_cb,OnFailure failure_cb,pw::async::Dispatcher & dispatcher)76 BrEdrConnectionRequest::CreateHciConnectionRequest(
77     hci::CommandChannel* command_channel,
78     std::optional<uint16_t> clock_offset,
79     std::optional<pw::bluetooth::emboss::PageScanRepetitionMode>
80         page_scan_repetition_mode,
81     OnTimeout timeout_cb,
82     OnFailure failure_cb,
83     pw::async::Dispatcher& dispatcher) {
84   std::unique_ptr<hci::BrEdrConnectionRequest> request =
85       std::make_unique<hci::BrEdrConnectionRequest>(
86           peer_id_, address_, std::move(timeout_cb), dispatcher);
87 
88   request->CreateConnection(command_channel,
89                             clock_offset,
90                             page_scan_repetition_mode,
91                             request_timeout_,
92                             std::move(failure_cb));
93 
94   // Record that the first create connection attempt was made (if not already
95   // attempted) for the outstanding HCI connection request for peer with id
96   // |peer_id_|
97   if (!first_create_connection_req_made_.value()) {
98     first_create_connection_req_made_.Set(dispatcher_.now());
99   }
100 
101   return request;
102 }
103 
ShouldRetry(hci::Error failure_mode)104 bool BrEdrConnectionRequest::ShouldRetry(hci::Error failure_mode) {
105   pw::chrono::SystemClock::time_point now = dispatcher_.now();
106   std::optional<pw::chrono::SystemClock::time_point>
107       first_create_conn_req_made = first_create_connection_req_made_.value();
108   return failure_mode.is(pw::bluetooth::emboss::StatusCode::PAGE_TIMEOUT) &&
109          first_create_conn_req_made.has_value() &&
110          now - *first_create_conn_req_made < kRetryWindowAfterFirstCreateConn;
111 }
112 }  // namespace bt::gap
113