| // Copyright 2017 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef GARNET_DRIVERS_BLUETOOTH_LIB_GAP_ADAPTER_H_ |
| #define GARNET_DRIVERS_BLUETOOTH_LIB_GAP_ADAPTER_H_ |
| |
| #include <memory> |
| #include <string> |
| |
| #include <lib/async/dispatcher.h> |
| #include <lib/fit/function.h> |
| #include <zircon/assert.h> |
| |
| #include "garnet/drivers/bluetooth/lib/data/domain.h" |
| #include "garnet/drivers/bluetooth/lib/gap/adapter_state.h" |
| #include "garnet/drivers/bluetooth/lib/gap/low_energy_connection_manager.h" |
| #include "garnet/drivers/bluetooth/lib/gap/remote_device_cache.h" |
| #include "garnet/drivers/bluetooth/lib/gatt/gatt.h" |
| #include "garnet/drivers/bluetooth/lib/sdp/server.h" |
| #include "lib/fxl/macros.h" |
| #include "lib/fxl/memory/weak_ptr.h" |
| #include "lib/fxl/synchronization/thread_checker.h" |
| |
| namespace btlib { |
| |
| namespace hci { |
| class LowEnergyAdvertiser; |
| class LowEnergyConnector; |
| class SequentialCommandRunner; |
| class Transport; |
| } // namespace hci |
| |
| namespace gap { |
| |
| class BrEdrConnectionManager; |
| class BrEdrDiscoveryManager; |
| class PairingDelegate; |
| class LowEnergyAdvertisingManager; |
| class LowEnergyDiscoveryManager; |
| |
| // Represents the host-subsystem state for a Bluetooth controller. All |
| // asynchronous callbacks are posted on the Loop on which this Adapter |
| // instance is created. |
| // |
| // This class is not thread-safe and it is intended to be created, deleted, and |
| // accessed on the same event loop. No internal locking is provided. |
| // |
| // NOTE: We currently only support primary controllers. AMP controllers are not |
| // supported. |
| class Adapter final { |
| public: |
| // There must be an async_t dispatcher registered as a default when an Adapter |
| // instance is created. The Adapter instance will use it for all of its |
| // asynchronous tasks. |
| // |
| // This will take ownership of |hci_device|. |
| explicit Adapter(fxl::RefPtr<hci::Transport> hci, |
| fbl::RefPtr<data::Domain> data_domain, |
| fbl::RefPtr<gatt::GATT> gatt); |
| ~Adapter(); |
| |
| // Returns a 128-bit UUID that uniquely identifies this adapter on the current |
| // system. |
| const std::string& identifier() const { return identifier_; } |
| |
| // Initializes the host-subsystem state for the HCI device this was created |
| // for. This performs the initial HCI transport set up. Returns false if an |
| // immediate error occurs. Otherwise this returns true and asynchronously |
| // notifies the caller on the initialization status via |callback|. |
| // |
| // After successful initialization, |transport_closed_callback| will be |
| // invoked when the underlying HCI transport closed for any reason (e.g. the |
| // device disappeared or the transport channels were closed for an unknown |
| // reason). The implementation is responsible for cleaning up this adapter by |
| // calling ShutDown(). |
| using InitializeCallback = fit::function<void(bool success)>; |
| bool Initialize(InitializeCallback callback, |
| fit::closure transport_closed_callback); |
| |
| // Shuts down this Adapter. Invokes |callback| when shut down has completed. |
| // TODO(armansito): This needs to do several things to potentially preserve |
| // the state of various sub-protocols. For now we keep the interface pretty |
| // simple. |
| void ShutDown(); |
| |
| // Returns true if the Initialize() sequence has started but not completed yet |
| // (i.e. the InitializeCallback that was passed to Initialize() has not yet |
| // been called). |
| bool IsInitializing() const { return init_state_ == State::kInitializing; } |
| |
| // Returns true if this Adapter has been fully initialized. |
| bool IsInitialized() const { return init_state_ == State::kInitialized; } |
| |
| // Returns the global adapter setting parameters. |
| const AdapterState& state() const { return state_; } |
| |
| // Returns a weak pointer to this adapter. |
| fxl::WeakPtr<Adapter> AsWeakPtr() { return weak_ptr_factory_.GetWeakPtr(); } |
| |
| // Returns this Adapter's remote device cache. |
| const RemoteDeviceCache& device_cache() const { return device_cache_; } |
| |
| // Returns this Adapter's BR/EDR connection manager. |
| BrEdrConnectionManager* bredr_connection_manager() const { |
| return bredr_connection_manager_.get(); |
| } |
| |
| // Returns this Adapter's BR/EDR discovery manager. |
| BrEdrDiscoveryManager* bredr_discovery_manager() const { |
| return bredr_discovery_manager_.get(); |
| } |
| |
| // Returns this Adapter's SDP server. |
| sdp::Server* sdp_server() const { return sdp_server_.get(); } |
| |
| // Returns this Adapter's LE discovery manager. |
| LowEnergyDiscoveryManager* le_discovery_manager() const { |
| ZX_DEBUG_ASSERT(le_discovery_manager_); |
| return le_discovery_manager_.get(); |
| } |
| |
| // Returns this Adapter's LE connection manager. |
| LowEnergyConnectionManager* le_connection_manager() const { |
| ZX_DEBUG_ASSERT(le_connection_manager_); |
| return le_connection_manager_.get(); |
| } |
| |
| // Returns this Adapter's LE advertising manager. |
| LowEnergyAdvertisingManager* le_advertising_manager() const { |
| ZX_DEBUG_ASSERT(le_advertising_manager_); |
| return le_advertising_manager_.get(); |
| } |
| |
| // Returns this Adapter's remote device cache. |
| RemoteDeviceCache* remote_device_cache() { return &device_cache_; } |
| |
| // Add a previously bonded device to the device cache and set it up for |
| // auto-connect procedures. |
| bool AddBondedDevice(const std::string& identifier, |
| const common::DeviceAddress& address, |
| const sm::PairingData& le_bond_data); |
| |
| // Assigns a pairing delegate to this adapter. This PairingDelegate and its |
| // I/O capabilities will be used for all future pairing procedures. Setting a |
| // new PairingDelegate cancels all ongoing pairing procedures. |
| void SetPairingDelegate(fxl::WeakPtr<PairingDelegate> delegate); |
| |
| // Returns true if any discovery process (LE or BR/EDR) is running on this |
| // adapter. |
| bool IsDiscovering() const; |
| |
| // Sets the Local Name of this adapter, for both BR/EDR discoverability and |
| // public LE services. |
| void SetLocalName(std::string name, hci::StatusCallback callback); |
| |
| // Sets the Device Class of this adapter. |
| void SetClassOfDevice(common::DeviceClass dev_class, |
| hci::StatusCallback callback); |
| |
| // Assign a callback to be notified when a connection is automatically |
| // established to a bonded LE device in the directed connectable mode (Vol 3, |
| // Part C, 9.3.3). |
| using AutoConnectCallback = fit::function<void(LowEnergyConnectionRefPtr)>; |
| void set_auto_connect_callback(AutoConnectCallback callback) { |
| auto_conn_cb_ = std::move(callback); |
| } |
| |
| private: |
| // Second step of the initialization sequence. Called by Initialize() when the |
| // first batch of HCI commands have been sent. |
| void InitializeStep2(InitializeCallback callback); |
| |
| // Third step of the initialization sequence. Called by InitializeStep2() when |
| // the second batch of HCI commands have been sent. |
| void InitializeStep3(InitializeCallback callback); |
| |
| // Fourth step of the initialization sequence. Called by InitializeStep3() |
| // when the third batch of HCI commands have been sent. |
| void InitializeStep4(InitializeCallback callback); |
| |
| // Builds and returns the HCI event mask based on our supported host side |
| // features and controller capabilities. This is used to mask events that we |
| // do not know how to handle. |
| uint64_t BuildEventMask(); |
| |
| // Builds and returns the LE event mask based on our supported host side |
| // features and controller capabilities. This is used to mask LE events that |
| // we do not know how to handle. |
| uint64_t BuildLEEventMask(); |
| |
| // Called by ShutDown() and during Initialize() in case of failure. This |
| // synchronously cleans up the transports and resets initialization state. |
| void CleanUp(); |
| |
| // Called by Transport after it has been unexpectedly closed. |
| void OnTransportClosed(); |
| |
| // Called when a directed connectable advertisement is received from a bonded |
| // LE device. This amounts to a connection request from a bonded peripheral |
| // which is handled by routing the request to |le_connection_manager_| to |
| // initiate a Direct Connection Establishment procedure (Vol 3, Part C, |
| // 9.3.8). |
| void OnLeAutoConnectRequest(const std::string& device_id); |
| |
| // Uniquely identifies this adapter on the current system. |
| std::string identifier_; |
| |
| async_dispatcher_t* dispatcher_; |
| fxl::RefPtr<hci::Transport> hci_; |
| |
| // Callback invoked to notify clients when the underlying transport is closed. |
| fit::closure transport_closed_cb_; |
| |
| // Parameters relevant to the initialization sequence. |
| // TODO(armansito): The Initialize()/ShutDown() pattern has become common |
| // enough in this project that it might be worth considering moving the |
| // init-state-keeping into an abstract base. |
| enum State { |
| kNotInitialized = 0, |
| kInitializing, |
| kInitialized, |
| }; |
| std::atomic<State> init_state_; |
| std::unique_ptr<hci::SequentialCommandRunner> init_seq_runner_; |
| |
| // Contains the global adapter state. |
| AdapterState state_; |
| |
| // The maximum LMP feature page that we will read. |
| size_t max_lmp_feature_page_index_; |
| |
| // Provides access to discovered, connected, and/or bonded remote Bluetooth |
| // devices. |
| RemoteDeviceCache device_cache_; |
| |
| // The data domain used by GAP to interact with L2CAP and RFCOMM layers. |
| fbl::RefPtr<data::Domain> data_domain_; |
| |
| // The GATT profile. We use this reference to add and remove data bearers and |
| // for service discovery. |
| fbl::RefPtr<gatt::GATT> gatt_; |
| |
| // Objects that abstract the controller for connection and advertising |
| // procedures. |
| // TODO(armansito): Move hci::LowEnergyScanner here. |
| std::unique_ptr<hci::LowEnergyAdvertiser> hci_le_advertiser_; |
| std::unique_ptr<hci::LowEnergyConnector> hci_le_connector_; |
| |
| // Objects that perform LE procedures. |
| std::unique_ptr<LowEnergyDiscoveryManager> le_discovery_manager_; |
| std::unique_ptr<LowEnergyConnectionManager> le_connection_manager_; |
| std::unique_ptr<LowEnergyAdvertisingManager> le_advertising_manager_; |
| |
| // Objects that perform BR/EDR procedures. |
| std::unique_ptr<BrEdrConnectionManager> bredr_connection_manager_; |
| std::unique_ptr<BrEdrDiscoveryManager> bredr_discovery_manager_; |
| std::unique_ptr<sdp::Server> sdp_server_; |
| |
| // Callback to propagate ownership of an auto-connected LE link. |
| AutoConnectCallback auto_conn_cb_; |
| |
| fxl::ThreadChecker thread_checker_; |
| |
| // This must remain the last member to make sure that all weak pointers are |
| // invalidating before other members are destroyed. |
| fxl::WeakPtrFactory<Adapter> weak_ptr_factory_; |
| |
| FXL_DISALLOW_COPY_AND_ASSIGN(Adapter); |
| }; |
| |
| } // namespace gap |
| } // namespace btlib |
| |
| #endif // GARNET_DRIVERS_BLUETOOTH_LIB_GAP_ADAPTER_H_ |