Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4b871ea6 authored by Jakub Pawlowski's avatar Jakub Pawlowski
Browse files

Add Connect and Disconnect methods to LowEnergyClient

Change-Id: Ibabfd44575b7ab1c8fc7a57b844956038dd571c4
parent 2331fed3
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -168,6 +168,12 @@ bool BluetoothLowEnergyBinderServer::StopMultiAdvertising(int client_id) {
  return true;
}

void BluetoothLowEnergyBinderServer::OnConnectionState(
      bluetooth::LowEnergyClient* client, int status,
      const char* address, bool connected) {
  VLOG(2) << __func__ << " address: " << address << " connected: " << connected;
}

void BluetoothLowEnergyBinderServer::OnScanResult(
    bluetooth::LowEnergyClient* client,
    const bluetooth::ScanResult& result) {
+2 −0
Original line number Diff line number Diff line
@@ -60,6 +60,8 @@ class BluetoothLowEnergyBinderServer
  bool StopMultiAdvertising(int client_id) override;

  // bluetooth::LowEnergyClient::Delegate overrides:
  void OnConnectionState(bluetooth::LowEnergyClient* client, int status,
                         const char* address, bool connected) override;
  void OnScanResult(bluetooth::LowEnergyClient* client,
                    const bluetooth::ScanResult& result) override;

+86 −2
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include <base/logging.h>

#include "service/adapter.h"
#include "service/common/bluetooth/util/address_helper.h"
#include "service/logging_helpers.h"
#include "stack/include/bt_types.h"
#include "stack/include/hcidefs.h"
@@ -334,6 +335,49 @@ LowEnergyClient::~LowEnergyClient() {
    StopScan();
}

bool LowEnergyClient::Connect(std::string address, bool is_direct) {
  VLOG(2) << __func__ << "Address: " << address << " is_direct: " << is_direct;

  bt_bdaddr_t bda;
  util::BdAddrFromString(address, &bda);

  bt_status_t status = hal::BluetoothGattInterface::Get()->
      GetClientHALInterface()->connect(client_id_, &bda, is_direct,
                                       BT_TRANSPORT_LE);
  if (status != BT_STATUS_SUCCESS) {
    LOG(ERROR) << "HAL call to connect failed";
    return false;
  }

  return true;
}

bool LowEnergyClient::Disconnect(std::string address) {
  VLOG(2) << __func__ << "Address: " << address;

  bt_bdaddr_t bda;
  util::BdAddrFromString(address, &bda);

  std::map<const bt_bdaddr_t, int>::iterator conn_id;
  {
    lock_guard<mutex> lock(connection_fields_lock_);
    conn_id = connection_ids_.find(bda);
    if (conn_id == connection_ids_.end()) {
      LOG(WARNING) << "Can't disconnect, no existing connection to " << address;
      return false;
    }
  }

  bt_status_t status = hal::BluetoothGattInterface::Get()->
      GetClientHALInterface()->disconnect(client_id_, &bda, conn_id->second);
  if (status != BT_STATUS_SUCCESS) {
    LOG(ERROR) << "HAL call to disconnect failed";
    return false;
  }

  return true;
}

void LowEnergyClient::SetDelegate(Delegate* delegate) {
  lock_guard<mutex> lock(delegate_mutex_);
  delegate_ = delegate;
@@ -513,6 +557,46 @@ void LowEnergyClient::ScanResultCallback(
  delegate_->OnScanResult(this, result);
}

void LowEnergyClient::ConnectCallback(
      hal::BluetoothGattInterface* gatt_iface, int conn_id, int status,
      int client_id, const bt_bdaddr_t& bda) {
  if (client_id != client_id_)
    return;

  VLOG(1) << __func__ << "client_id: " << client_id << " status: " << status;

  {
    lock_guard<mutex> lock(connection_fields_lock_);
    auto success = connection_ids_.emplace(bda, conn_id);
    if (!success.second) {
      LOG(ERROR) << __func__ << " Insertion into connection_ids_ failed!";
    }
  }

  if (delegate_)
    delegate_->OnConnectionState(this, status, BtAddrString(&bda).c_str(),
                                 true);
}

void LowEnergyClient::DisconnectCallback(
      hal::BluetoothGattInterface* gatt_iface, int conn_id, int status,
      int client_id, const bt_bdaddr_t& bda) {
  if (client_id != client_id_)
    return;

  VLOG(1) << __func__ << " client_id: " << client_id << " status: " << status;
  {
    lock_guard<mutex> lock(connection_fields_lock_);
    if (!connection_ids_.erase(bda)) {
      LOG(ERROR) << __func__ << " Erasing from connection_ids_ failed!";
    }
  }

  if (delegate_)
    delegate_->OnConnectionState(this, status, BtAddrString(&bda).c_str(),
                                 false);
}

void LowEnergyClient::MultiAdvEnableCallback(
    hal::BluetoothGattInterface* gatt_iface,
    int client_id, int status) {
+33 −1
Original line number Diff line number Diff line
@@ -35,6 +35,12 @@

namespace bluetooth {

struct ConnComparator {
    bool operator()(const bt_bdaddr_t& a, const bt_bdaddr_t& b) const {
        return memcmp(&a, &b, sizeof(bt_bdaddr_t)) < 0;
    }
};

class Adapter;

// A LowEnergyClient represents an application's handle to perform various
@@ -55,6 +61,10 @@ class LowEnergyClient : private hal::BluetoothGattInterface::ClientObserver,
    virtual void OnScanResult(LowEnergyClient* client,
                              const ScanResult& scan_result) = 0;

    // Called asynchronously to notify the delegate of connection state change
    virtual void OnConnectionState(LowEnergyClient* client, int status,
                                   const char* address, bool connected) = 0;

   private:
    DISALLOW_COPY_AND_ASSIGN(Delegate);
  };
@@ -70,6 +80,15 @@ class LowEnergyClient : private hal::BluetoothGattInterface::ClientObserver,
  // Callback type used to return the result of asynchronous operations below.
  using StatusCallback = std::function<void(BLEStatus)>;

  // Initiates a BLE connection do device with address |address|. If
  // |is_direct| is set, use direct connect procedure. Return true on success
  //, false otherwise.
  bool Connect(std::string address, bool is_direct);

  // Disconnect from previously connected BLE device with address |address|.
  // Return true on success, false otherwise.
  bool Disconnect(std::string address);

  // Initiates a BLE device scan for this client using the given |settings| and
  // |filters|. See the documentation for ScanSettings and ScanFilter for how
  // these parameters can be configured. Return true on success, false
@@ -123,6 +142,13 @@ class LowEnergyClient : private hal::BluetoothGattInterface::ClientObserver,
  void ScanResultCallback(
      hal::BluetoothGattInterface* gatt_iface,
      const bt_bdaddr_t& bda, int rssi, uint8_t* adv_data) override;

  void ConnectCallback(
      hal::BluetoothGattInterface* gatt_iface, int conn_id, int status,
      int client_id, const bt_bdaddr_t& bda) override;
  void DisconnectCallback(
      hal::BluetoothGattInterface* gatt_iface, int conn_id, int status,
      int client_id, const bt_bdaddr_t& bda) override;
  void MultiAdvEnableCallback(
      hal::BluetoothGattInterface* gatt_iface,
      int client_id, int status) override;
@@ -190,6 +216,12 @@ class LowEnergyClient : private hal::BluetoothGattInterface::ClientObserver,
  std::mutex delegate_mutex_;
  Delegate* delegate_;

  // Protects device connection related members below.
  std::mutex connection_fields_lock_;

  // Maps bluetooth address to connection id
  std::map<const bt_bdaddr_t, int, ConnComparator> connection_ids_;

  DISALLOW_COPY_AND_ASSIGN(LowEnergyClient);
};

+72 −4
Original line number Diff line number Diff line
@@ -27,6 +27,9 @@

using ::testing::_;
using ::testing::Return;
using ::testing::Pointee;
using ::testing::DoAll;
using ::testing::Invoke;

namespace bluetooth {
namespace {
@@ -74,7 +77,7 @@ class MockGattHandler

class TestDelegate : public LowEnergyClient::Delegate {
 public:
  TestDelegate() : scan_result_count_(0) {
  TestDelegate() : scan_result_count_(0), connection_state_count_(0) {
  }

  ~TestDelegate() override = default;
@@ -82,6 +85,14 @@ class TestDelegate : public LowEnergyClient::Delegate {
  int scan_result_count() const { return scan_result_count_; }
  const ScanResult& last_scan_result() const { return last_scan_result_; }

  int connection_state_count() const { return connection_state_count_; }

  void OnConnectionState(LowEnergyClient* client, int status,
                         const char* address, bool connected)  {
    ASSERT_TRUE(client);
    connection_state_count_++;
  }

  void OnScanResult(LowEnergyClient* client, const ScanResult& scan_result) {
    ASSERT_TRUE(client);
    scan_result_count_++;
@@ -92,6 +103,8 @@ class TestDelegate : public LowEnergyClient::Delegate {
  int scan_result_count_;
  ScanResult last_scan_result_;

  int connection_state_count_;

  DISALLOW_COPY_AND_ASSIGN(TestDelegate);
};

@@ -937,5 +950,60 @@ TEST_F(LowEnergyClientPostRegisterTest, ScanRecord) {
  le_client_->SetDelegate(nullptr);
}

MATCHER_P(BitEq, x, std::string(negation ? "isn't" : "is") +
                        " bitwise equal to " + ::testing::PrintToString(x)) {
  static_assert(sizeof(x) == sizeof(arg), "Size mismatch");
  return std::memcmp(&arg, &x, sizeof(x)) == 0;
}

TEST_F(LowEnergyClientPostRegisterTest, Connect) {
  const bt_bdaddr_t kTestAddress = {
    { 0x01, 0x02, 0x03, 0x0A, 0x0B, 0x0C }
  };
  const char kTestAddressStr[] = "01:02:03:0A:0B:0C";
  const bool kTestDirect = false;
  const int connId = 12;

  TestDelegate delegate;
  le_client_->SetDelegate(&delegate);

  // TODO(jpawlowski): NotifyConnectCallback should be called after returning
  // success, fix it when it becomes important.
  // These should succeed and result in a HAL call
  EXPECT_CALL(*mock_handler_, Connect(le_client_->GetInstanceId(),
          Pointee(BitEq(kTestAddress)), kTestDirect, BT_TRANSPORT_LE))
      .Times(1)
      .WillOnce(DoAll(
        Invoke([&](int client_id, const bt_bdaddr_t *bd_addr, bool is_direct,
                   int transport){
          fake_hal_gatt_iface_->NotifyConnectCallback(connId, BT_STATUS_SUCCESS,
                                                      client_id, *bd_addr);
        }),
        Return(BT_STATUS_SUCCESS)));

  EXPECT_TRUE(le_client_->Connect(kTestAddressStr, kTestDirect));
  EXPECT_EQ(1, delegate.connection_state_count());

  // TODO(jpawlowski): same as above
  // These should succeed and result in a HAL call
  EXPECT_CALL(*mock_handler_, Disconnect(le_client_->GetInstanceId(),
        Pointee(BitEq(kTestAddress)), connId))
      .Times(1)
      .WillOnce(DoAll(
        Invoke([&](int client_id, const bt_bdaddr_t *bd_addr, int connId){
          fake_hal_gatt_iface_->NotifyDisconnectCallback(connId,
                                                         BT_STATUS_SUCCESS,
                                                         client_id, *bd_addr);
        }),
        Return(BT_STATUS_SUCCESS)));

  EXPECT_TRUE(le_client_->Disconnect(kTestAddressStr));
  EXPECT_EQ(2, delegate.connection_state_count());

  le_client_->SetDelegate(nullptr);
  ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
}


}  // namespace
}  // namespace bluetooth