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 #pragma once
16 #include "pw_bluetooth_sapphire/internal/host/common/identifier.h"
17 #include "pw_bluetooth_sapphire/internal/host/transport/command_channel.h"
18 #include "pw_bluetooth_sapphire/internal/host/transport/error.h"
19 
20 namespace bt::hci {
21 
22 // The request can be in three possible states:
23 enum class RequestState : uint8_t {
24   // The connection request is still pending
25   kPending,
26   // The connection request was intentionally cancelled
27   kCanceled,
28   // The connection request timed out whilst waiting for a response
29   kTimedOut,
30   // The connection request has succeeded
31   kSuccess,
32 };
33 
34 // Bitmask enabling all packets types. By enabling as many as we can, we expect
35 // the controller to only use the ones it supports
36 constexpr hci_spec::PacketTypeType kEnableAllPacketTypes =
37     static_cast<hci_spec::PacketTypeType>(
38         hci_spec::PacketTypeBits::kEnableDM1) |
39     static_cast<hci_spec::PacketTypeType>(
40         hci_spec::PacketTypeBits::kEnableDH1) |
41     static_cast<hci_spec::PacketTypeType>(
42         hci_spec::PacketTypeBits::kEnableDM3) |
43     static_cast<hci_spec::PacketTypeType>(
44         hci_spec::PacketTypeBits::kEnableDH3) |
45     static_cast<hci_spec::PacketTypeType>(
46         hci_spec::PacketTypeBits::kEnableDM5) |
47     static_cast<hci_spec::PacketTypeType>(hci_spec::PacketTypeBits::kEnableDH5);
48 
49 // This class represents a pending request by the BrEdr connector to initiate an
50 // outgoing connection. It tracks the state of that request and is responsible
51 // for running a call back when the connection status updates
52 //
53 // There should be only one of these at any given time, an it is managed by the
54 // BrEdrConnectionManager
55 class BrEdrConnectionRequest final {
56  public:
57   using OnCompleteDelegate = fit::function<void(Result<>, PeerId)>;
58 
BrEdrConnectionRequest(PeerId id,DeviceAddress addr,fit::closure timeout_callback,pw::async::Dispatcher & dispatcher)59   BrEdrConnectionRequest(PeerId id,
60                          DeviceAddress addr,
61                          fit::closure timeout_callback,
62                          pw::async::Dispatcher& dispatcher)
63       : state_(RequestState::kPending),
64         peer_id_(id),
65         peer_address_(addr),
66         timeout_task_(dispatcher),
67         weak_self_(this) {
68     timeout_task_.set_function(
69         [timeout_cb = std::move(timeout_callback)](pw::async::Context /*ctx*/,
70                                                    pw::Status status) {
71           if (status.ok()) {
72             timeout_cb();
73           }
74         });
75   }
76 
77   ~BrEdrConnectionRequest();
78 
79   // Send the CreateConnection command over |command_channel| and begin the
80   // create connection procedure. If the command status returns an error, then
81   // |on_command_fail| called. The |clock_offset| and |page_scan_repetition|
82   // parameters are standard parameters found in Core Spec 5.0, Vol 2, Part E,
83   // section 7.1.5
84   // |timeout| is the command timeout; this is how long we give from the point
85   // we receive the CommandStatus response from the controller until we cancel
86   // the procedure if we have not received ConnectionComplete
87   void CreateConnection(
88       CommandChannel* command_channel,
89       std::optional<uint16_t> clock_offset,
90       std::optional<pw::bluetooth::emboss::PageScanRepetitionMode>
91           page_scan_repetition_mode,
92       pw::chrono::SystemClock::duration timeout,
93       OnCompleteDelegate on_command_fail);
94 
peer_id()95   PeerId peer_id() const { return peer_id_; }
peer_address()96   DeviceAddress peer_address() const { return peer_address_; }
97 
98   // Complete the request, either successfully or not, and return the status
99   // of the Request - In the case of Timeout or Cancellation, this will be
100   // different from the status sent by the controller.
101   Result<> CompleteRequest(Result<> status);
102 
103   // Mark the request as Timed out; triggered when the command timeout runs out
104   // and called by BrEdrConnectionManager;
105   void Timeout();
106 
107   // Attempt to mark the request as Canceled, and returns true if successful.
108   // This is called during cleanup to ensure connection procedures are not
109   // orphaned
110   bool Cancel();
111 
112  private:
113   RequestState state_;
114   PeerId peer_id_;
115   DeviceAddress peer_address_;
116 
117   SmartTask timeout_task_;
118 
119   // Keep this as the last member to make sure that all weak pointers are
120   // invalidated before other members get destroyed.
121   WeakSelf<BrEdrConnectionRequest> weak_self_;
122 };
123 
124 }  // namespace bt::hci
125