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