text: // Copyright 2018 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 SRC_CONNECTIVITY_BLUETOOTH_HCI_EMULATOR_DEVICE_H_
  #define SRC_CONNECTIVITY_BLUETOOTH_HCI_EMULATOR_DEVICE_H_
  
  #include <fuchsia/bluetooth/test/cpp/fidl.h>
  #include <fuchsia/hardware/bluetooth/c/fidl.h>
  #include <fuchsia/hardware/bt/hci/c/banjo.h>
  #include <fuchsia/hardware/test/c/banjo.h>
  #include <lib/async-loop/cpp/loop.h>
  #include <lib/async-loop/default.h>
  #include <lib/ddk/debug.h>
  #include <lib/ddk/device.h>
  #include <lib/ddk/driver.h>
  #include <lib/fidl/cpp/binding.h>
  #include <zircon/compiler.h>
  #include <zircon/syscalls.h>
  #include <zircon/types.h>
  
  #include <queue>
  #include <unordered_map>
  
  #include "src/connectivity/bluetooth/core/bt-host/testing/fake_controller.h"
  #include "src/connectivity/bluetooth/hci/emulator/peer.h"
  #include "src/connectivity/bluetooth/lib/fidl/hanging_getter.h"
  
  namespace bt_hci_emulator {
  
  enum class Channel {
    ACL,
    COMMAND,
    SNOOP,
    EMULATOR,
  };
  
  class Device : public fuchsia::bluetooth::test::HciEmulator {
   public:
    explicit Device(zx_device_t* device);
  
    zx_status_t Bind(std::string_view name);
    void Unbind();
    void Release();
  
    zx_status_t HciMessage(fidl_incoming_msg_t* msg, fidl_txn_t* txn);
    zx_status_t EmulatorMessage(fidl_incoming_msg_t* msg, fidl_txn_t* txn);
    zx_status_t GetProtocol(uint32_t proto_id, void* out_proto);
    zx_status_t OpenChan(Channel chan_type, zx_handle_t chan);
  
    static zx_status_t OpenCommandChannel(void* ctx, zx_handle_t channel);
    static zx_status_t OpenAclDataChannel(void* ctx, zx_handle_t channel);
    static zx_status_t OpenSnoopChannel(void* ctx, zx_handle_t channel);
    static zx_status_t OpenEmulatorChannel(void* ctx, zx_handle_t channel);
  
   private:
    void StartEmulatorInterface(zx::channel chan);
  
    // fuchsia::bluetooth::test::HciEmulator overrides:
    void Publish(fuchsia::bluetooth::test::EmulatorSettings settings,
                 PublishCallback callback) override;
    void AddLowEnergyPeer(fuchsia::bluetooth::test::LowEnergyPeerParameters params,
                          fidl::InterfaceRequest<fuchsia::bluetooth::test::Peer> request,
                          AddLowEnergyPeerCallback callback) override;
    void AddBredrPeer(fuchsia::bluetooth::test::BredrPeerParameters params,
                      fidl::InterfaceRequest<fuchsia::bluetooth::test::Peer> request,
                      AddBredrPeerCallback callback) override;
    void WatchControllerParameters(WatchControllerParametersCallback callback) override;
    void WatchLeScanStates(WatchLeScanStatesCallback callback) override;
    void WatchLegacyAdvertisingStates(WatchLegacyAdvertisingStatesCallback callback) override;
  
    // Helper function used to initialize BR/EDR and LE peers.
    void AddPeer(std::unique_ptr<Peer> peer);
  
    void OnControllerParametersChanged();
    void OnLegacyAdvertisingStateChanged();
  
    // Remove the bt-hci device.
    void UnpublishHci();
  
    void OnPeerConnectionStateChanged(const bt::DeviceAddress& address,
                                      bt::hci::ConnectionHandle handle, bool connected,
                                      bool canceled);
  
    static constexpr fuchsia_hardware_bluetooth_Hci_ops_t hci_fidl_ops_ = {
        .OpenCommandChannel = OpenCommandChannel,
        .OpenAclDataChannel = OpenAclDataChannel,
        .OpenSnoopChannel = OpenSnoopChannel,
    };
  
    static constexpr fuchsia_hardware_bluetooth_Emulator_ops_t emul_fidl_ops_ = {
        .Open = OpenEmulatorChannel,
    };
  
    async::Loop loop_;
  
    zx_device_t* const parent_;
  
    // The device that implements the bt-hci protocol. |hci_dev_| will only be accessed and modified
    // on the following threads/conditions:
    //   1. It only gets initialized on the |loop_| dispatcher during Publish().
    //   2. Unpublished when the HciEmulator FIDL channel (i.e. |binding_|) gets closed, which gets
    //      processed on the |loop_| dispatcher.
    //   3. Unpublished in the DDK Unbind() call which runs on a devhost thread. This is guaranteed
    //      not to happen concurrently with #1 and #2 as Unbind always drains and joins the |loop_|
    //      threads before removing devices.
    zx_device_t* hci_dev_;
  
    // The device that implements the bt-emulator protocol.
    zx_device_t* emulator_dev_;
  
    // All objects below are only accessed on the |loop_| dispatcher.
    fbl::RefPtr<bt::testing::FakeController> fake_device_;
  
    // Binding for fuchsia.bluetooth.test.HciEmulator channel. |binding_| is only accessed on
    // |loop_|'s dispatcher.
    fidl::Binding<fuchsia::bluetooth::test::HciEmulator> binding_;
  
    // List of active peers that have been registered with us.
    std::unordered_map<bt::DeviceAddress, std::unique_ptr<Peer>> peers_;
  
    bt_lib_fidl::HangingGetter<fuchsia::bluetooth::test::ControllerParameters>
        controller_parameters_getter_;
    bt_lib_fidl::HangingVectorGetter<fuchsia::bluetooth::test::LegacyAdvertisingState>
        legacy_adv_state_getter_;
  };
  
  }  // namespace bt_hci_emulator
  
  #endif  // SRC_CONNECTIVITY_BLUETOOTH_HCI_EMULATOR_DEVICE_H_
  