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