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 <lib/fit/function.h>
17 
18 #include "pw_bluetooth_sapphire/internal/host/common/assert.h"
19 #include "pw_bluetooth_sapphire/internal/host/common/device_address.h"
20 #include "pw_bluetooth_sapphire/internal/host/common/macros.h"
21 #include "pw_bluetooth_sapphire/internal/host/hci-spec/protocol.h"
22 #include "pw_bluetooth_sapphire/internal/host/transport/command_channel.h"
23 #include "pw_bluetooth_sapphire/internal/host/transport/control_packets.h"
24 #include "pw_bluetooth_sapphire/internal/host/transport/error.h"
25 #include "pw_bluetooth_sapphire/internal/host/transport/link_type.h"
26 #include "pw_bluetooth_sapphire/internal/host/transport/transport.h"
27 
28 namespace bt::hci {
29 
30 // A Connection represents a logical link connection to a peer. It maintains
31 // link-specific configuration parameters (such as the connection handle) and
32 // state (e.g kConnected/kDisconnected). Controller procedures that are related
33 // to managing a logical link are performed by a Connection, e.g. disconnecting
34 // the link.
35 //
36 // Connection instances are intended to be uniquely owned. The owner of an
37 // instance is also the owner of the underlying link and the lifetime of a
38 // Connection determines the lifetime of the link.
39 //
40 // Connection is not expected to be constructed directly. Users should instead
41 // construct a specialization based on the link type: LowEnergyConnection,
42 // BrEdrConnection, or ScoConnection,
43 class Connection {
44  public:
45   enum class State {
46     // Default state of a newly created Connection. This is the only connection
47     // state that is
48     // considered "open".
49     kConnected,
50 
51     // HCI Disconnect command has been sent, but HCI Disconnection Complete
52     // event has not yet been
53     // received. This state is skipped when the disconnection is initiated by
54     // the peer.
55     kWaitingForDisconnectionComplete,
56 
57     // HCI Disconnection Complete event has been received.
58     kDisconnected
59   };
60 
61   // The destructor closes this connection.
62   virtual ~Connection();
63 
64   // Returns a string representation.
65   virtual std::string ToString() const;
66 
67   // Returns the 12-bit connection handle of this connection. This handle is
68   // used to identify an individual logical link maintained by the controller.
handle()69   hci_spec::ConnectionHandle handle() const { return handle_; }
70 
71   // The local device address used while establishing the connection.
local_address()72   const DeviceAddress& local_address() const { return local_address_; }
73 
74   // The peer address used while establishing the connection.
peer_address()75   const DeviceAddress& peer_address() const { return peer_address_; }
76 
state()77   State state() const { return conn_state_; }
78 
79   // Assigns a callback that will be run when the peer disconnects.
80   using PeerDisconnectCallback = fit::function<void(
81       const Connection& connection, pw::bluetooth::emboss::StatusCode reason)>;
set_peer_disconnect_callback(PeerDisconnectCallback callback)82   void set_peer_disconnect_callback(PeerDisconnectCallback callback) {
83     peer_disconnect_callback_ = std::move(callback);
84   }
85 
86   // Send HCI Disconnect and set state to closed. Must not be called on an
87   // already disconnected connection.
88   virtual void Disconnect(pw::bluetooth::emboss::StatusCode reason);
89 
90  protected:
91   // |on_disconnection_complete| will be called when the disconnection complete
92   // event is received, which may be after this object is destroyed (which is
93   // why this isn't a virtual method).
94   Connection(hci_spec::ConnectionHandle handle,
95              const DeviceAddress& local_address,
96              const DeviceAddress& peer_address,
97              Transport::WeakPtr hci,
98              fit::callback<void()> on_disconnection_complete);
99 
hci()100   const Transport::WeakPtr& hci() { return hci_; }
101 
peer_disconnect_callback()102   PeerDisconnectCallback& peer_disconnect_callback() {
103     return peer_disconnect_callback_;
104   }
105 
106  private:
107   // Checks |event|, unregisters link, and clears pending packets count.
108   // If the disconnection was initiated by the peer, call
109   // |peer_disconnect_callback|. Returns true if event was valid and for this
110   // connection. This method is static so that it can be called in an event
111   // handler after this object has been destroyed.
112   static CommandChannel::EventCallbackResult OnDisconnectionComplete(
113       const WeakSelf<Connection>::WeakPtr& self,
114       hci_spec::ConnectionHandle handle,
115       const EventPacket& event,
116       fit::callback<void()> on_disconnection_complete);
117 
118   hci_spec::ConnectionHandle handle_;
119 
120   // Addresses used while creating the link.
121   DeviceAddress local_address_;
122   DeviceAddress peer_address_;
123 
124   PeerDisconnectCallback peer_disconnect_callback_;
125 
126   State conn_state_;
127 
128   Transport::WeakPtr hci_;
129 
130   WeakSelf<Connection> weak_self_;
131 
132   BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(Connection);
133 };
134 
135 }  // namespace bt::hci
136