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

Commit 76992ce2 authored by Jakub Tyszkowski's avatar Jakub Tyszkowski Committed by Jakub Pawlowski
Browse files

stack: Periodic advertising scanner implementation

This adds the ble_scanner_hci_interface for periodic advertising scan
and all the low level HCI commands and event handlers.

Bug: 150670922
Tag: #feature
Sponsor: jpawlowski@
Test: compilation
Change-Id: I20e7057a8806c5ca8ef9e7261e1c2b446135cbed
parent ad3087af
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -103,6 +103,7 @@ cc_library_static {
        "btm/ble_advertiser_hci_interface.cc",
        "acl/btm_acl.cc",
        "acl/ble_acl.cc",
        "btm/ble_scanner_hci_interface.cc",
        "btm/btm_ble.cc",
        "btm/btm_ble_addr.cc",
        "btm/btm_ble_adv_filter.cc",
+1 −0
Original line number Diff line number Diff line
@@ -77,6 +77,7 @@ static_library("stack") {
    "bnep/bnep_main.cc",
    "bnep/bnep_utils.cc",
    "btm/ble_advertiser_hci_interface.cc",
    "btm/ble_scanner_hci_interface.cc",
    "btm/btm_acl.cc",
    "btm/btm_ble.cc",
    "btm/btm_ble_addr.cc",
+426 −0
Original line number Diff line number Diff line
/*
 * Copyright 2019 HIMSA II K/S - www.himsa.com.
 * Represented by EHIMA - www.ehima.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "ble_scanner_hci_interface.h"

#include <base/bind.h>

#include "acl_api.h"
#include "device/include/controller.h"
#include "hcidefs.h"
#include "hcimsgs.h"
#include "log/log.h"

namespace {
BleScannerHciInterface* instance = nullptr;

static void status_callback(base::Callback<void(uint8_t)> cb, uint8_t* data,
                            uint16_t len) {
  uint8_t status;

  LOG_ASSERT(len == 1) << "Received bad response length: " << len;
  STREAM_TO_UINT8(status, data);

  DVLOG(1) << __func__ << " Received status_cb";
  cb.Run(status);
}

static void status_handle_callback(base::Callback<void(uint8_t, uint16_t)> cb,
                                   uint8_t* data, uint16_t len) {
  uint8_t status;
  uint16_t handle = HCI_INVALID_HANDLE;

  LOG_ASSERT((len > 0) && (len < 4)) << "Received bad response length: " << len;
  uint8_t* pp = data;
  STREAM_TO_UINT8(status, pp);

  if (status == HCI_SUCCESS) {
    LOG_ASSERT(len == 3) << "Received bad response length: " << len;

    STREAM_TO_UINT16(handle, pp);
    handle = handle & 0x0EFF;

    DVLOG(1) << __func__ << " Received status_handle_callback";
  } else {
    DVLOG(1) << __func__ << " hci response error code: " << int{status};
  }
  cb.Run(status, handle);
}

/**
 * BleScannerHciInterface allows the caller to sync to a periodic advertising
 * train and receive periodic advertising data events through a registered
 * observer's callbacks. It also provides a synchronisation transfer API,
 * including in-controller allow list support. The right feature-complete
 * interface implementation is chosen during the init phase based on the
 * controller's list of supported features.
 */
class BleScannerImplBase : public BleScannerHciInterface {
 public:
  void SetScanEventObserver(ScanEventObserver* observer) override {
    VLOG(1) << __func__;
    // TODO: Support multiple observers if ever needed.
    scan_event_observer = observer;
  }

  void PeriodicScanStart(uint8_t options, uint8_t set_id, uint8_t adv_addr_type,
                         const RawAddress& adv_addr, uint16_t skip_num,
                         uint16_t sync_timeout,
                         uint8_t sync_cte_type) override {
    VLOG(1) << __func__;
    btsnd_hcic_ble_periodic_advertising_create_sync(
        options, set_id, adv_addr_type, adv_addr, skip_num, sync_timeout,
        sync_cte_type);
  }

  void PeriodicScanCancelStart(status_cb command_complete) override {
    VLOG(1) << __func__;
    btsnd_hcic_ble_periodic_advertising_create_sync_cancel(
        base::Bind(&status_callback, std::move(command_complete)));
  }

  void PeriodicScanTerminate(uint16_t sync_handle,
                             status_cb command_complete) override {
    VLOG(1) << __func__;
    btsnd_hcic_ble_periodic_advertising_terminate_sync(
        sync_handle, base::Bind(&status_callback, std::move(command_complete)));
  }

  void PeriodicScanResultEvtEnable(uint16_t sync_handle, bool enable,
                                   status_cb command_complete) override {
    VLOG(1) << __func__;
    btsnd_hcic_ble_set_periodic_advertising_receive_enable(
        sync_handle, enable,
        base::Bind(&status_callback, std::move(command_complete)));
  }

  void PeriodicAdvertiserListGetSize(
      BleScannerHciInterface::list_size_cb command_complete) override {
    VLOG(1) << __func__;
    command_complete.Run(
        controller_get_interface()->get_ble_periodic_advertiser_list_size());
  }

  void PeriodicAdvertiserListAddDevice(uint8_t adv_addr_type,
                                       RawAddress& adv_addr, uint8_t set_id,
                                       status_cb command_complete) override {
    VLOG(1) << __func__;
    btsnd_hci_ble_add_device_to_periodic_advertiser_list(
        adv_addr_type, adv_addr, set_id,
        base::Bind(&status_callback, std::move(command_complete)));
  }

  void PeriodicAdvertiserListRemoveDevice(uint8_t adv_addr_type,
                                          RawAddress& adv_addr, uint8_t set_id,
                                          status_cb command_complete) override {
    VLOG(1) << __func__;
    btsnd_hci_ble_remove_device_from_periodic_advertiser_list(
        adv_addr_type, adv_addr, set_id,
        base::Bind(&status_callback, std::move(command_complete)));
  }

  void PeriodicAdvertiserListClear(status_cb command_complete) override {
    VLOG(1) << __func__;
    btsnd_hci_ble_clear_periodic_advertiser_list(
        base::Bind(&status_callback, std::move(command_complete)));
  };

  void PeriodicAdvSyncTransfer(
      const RawAddress& bd_addr, uint16_t service_data, uint16_t sync_handle,
      BleScannerHciInterface::handle_cb command_complete) override {
    VLOG(1) << __func__;
    uint16_t acl_handle = acl_get_hci_handle_for_hcif(bd_addr, BT_TRANSPORT_LE);

    if (acl_handle == HCI_INVALID_HANDLE) {
      LOG(ERROR) << __func__
                 << ": Wrong mode: no LE link exist or LE not supported";
      return;
    }

    btsnd_hcic_ble_periodic_advertising_sync_transfer(
        acl_handle, service_data, sync_handle,
        base::Bind(&status_handle_callback, std::move(command_complete)));
  }

  void PeriodicAdvSetInfoTransfer(const RawAddress& bd_addr,
                                  uint16_t service_data, uint8_t adv_handle,
                                  handle_cb command_complete) override {
    VLOG(1) << __func__;
    uint16_t acl_handle = acl_get_hci_handle_for_hcif(bd_addr, BT_TRANSPORT_LE);

    if (acl_handle == HCI_INVALID_HANDLE) {
      LOG(ERROR) << __func__
                 << ": Wrong mode: no LE link exist or LE not supported";
      return;
    }

    btsnd_hcic_ble_periodic_advertising_set_info_transfer(
        acl_handle, service_data, adv_handle,
        base::Bind(&status_handle_callback, std::move(command_complete)));
  }

  void SetPeriodicAdvSyncTransferParams(const RawAddress& bd_addr, uint8_t mode,
                                        uint16_t skip, uint16_t sync_timeout,
                                        uint8_t cte_type, bool set_defaults,
                                        status_cb command_complete) override {
    VLOG(1) << __func__;
    uint16_t acl_handle = acl_get_hci_handle_for_hcif(bd_addr, BT_TRANSPORT_LE);

    if (acl_handle == HCI_INVALID_HANDLE) {
      LOG(ERROR) << __func__
                 << ": Wrong mode: no LE link exist or LE not supported";
      return;
    }

    if (set_defaults)
      btsnd_hcic_ble_set_default_periodic_advertising_sync_transfer_params(
          acl_handle, mode, skip, sync_timeout, cte_type,
          base::Bind(&status_callback, std::move(command_complete)));
    else
      btsnd_hcic_ble_set_periodic_advertising_sync_transfer_params(
          acl_handle, mode, skip, sync_timeout, cte_type,
          base::Bind(&status_callback, std::move(command_complete)));
  }

  void OnPeriodicAdvSyncEstablished(uint8_t status, uint16_t sync_handle,
                                    uint8_t adv_sid, uint8_t adv_addr_type,
                                    RawAddress adv_addr, uint8_t adv_phy,
                                    uint16_t adv_interval,
                                    uint8_t adv_clock_accuracy) {
    if (scan_event_observer) {
      scan_event_observer->OnPeriodicScanEstablished(
          status, sync_handle, adv_sid, adv_addr_type, adv_addr, adv_phy,
          adv_interval, adv_clock_accuracy);
    }
  }

  void OnPeriodicScanResult(uint16_t sync_handle, uint8_t tx_power, int8_t rssi,
                            uint8_t cte_type, uint8_t pkt_data_status,
                            uint8_t pkt_data_len, uint8_t* p_pkt_data) {
    // The observer should handle the caching and reassembly of the fragmented
    // packet.
    if (scan_event_observer) {
      scan_event_observer->OnPeriodicScanResult(sync_handle, tx_power, rssi,
                                                cte_type, pkt_data_status,
                                                pkt_data_len, p_pkt_data);
    }
  }

  void OnPeriodicSyncLost(uint16_t sync_handle) {
    if (scan_event_observer)
      scan_event_observer->OnPeriodicScanLost(sync_handle);
  }

 private:
  ScanEventObserver* scan_event_observer = nullptr;
};

class BleScannerListImpl : public virtual BleScannerImplBase {
  void PeriodicAdvertiserListAddDevice(uint8_t adv_addr_type,
                                       RawAddress& adv_addr, uint8_t set_id,
                                       status_cb command_complete) override {
    VLOG(1) << __func__;
    btsnd_hci_ble_add_device_to_periodic_advertiser_list(
        adv_addr_type, adv_addr, set_id,
        base::Bind(&status_callback, std::move(command_complete)));
  }

  void PeriodicAdvertiserListRemoveDevice(uint8_t adv_addr_type,
                                          RawAddress& adv_addr, uint8_t set_id,
                                          status_cb command_complete) override {
    VLOG(1) << __func__;
    btsnd_hci_ble_remove_device_from_periodic_advertiser_list(
        adv_addr_type, adv_addr, set_id,
        base::Bind(&status_callback, std::move(command_complete)));
  }

  void PeriodicAdvertiserListClear(status_cb command_complete) override {
    VLOG(1) << __func__;
    btsnd_hci_ble_clear_periodic_advertiser_list(
        base::Bind(&status_callback, std::move(command_complete)));
  };
};

class BleScannerSyncTransferImpl : public virtual BleScannerImplBase {
  void PeriodicAdvSyncTransfer(
      const RawAddress& bd_addr, uint16_t service_data, uint16_t sync_handle,
      BleScannerHciInterface::handle_cb command_complete) override {
    uint16_t acl_handle = acl_get_hci_handle_for_hcif(bd_addr, BT_TRANSPORT_LE);

    if (acl_handle == HCI_INVALID_HANDLE) {
      LOG(ERROR) << __func__
                 << ": Wrong mode: no LE link exist or LE not supported";
      return;
    }

    btsnd_hcic_ble_periodic_advertising_sync_transfer(
        acl_handle, service_data, sync_handle,
        base::Bind(&status_handle_callback, std::move(command_complete)));
  }

  void PeriodicAdvSetInfoTransfer(const RawAddress& bd_addr,
                                  uint16_t service_data, uint8_t adv_handle,
                                  handle_cb command_complete) override {
    uint16_t acl_handle = acl_get_hci_handle_for_hcif(bd_addr, BT_TRANSPORT_LE);

    if (acl_handle == HCI_INVALID_HANDLE) {
      LOG(ERROR) << __func__
                 << ": Wrong mode: no LE link exist or LE not supported";
      return;
    }

    btsnd_hcic_ble_periodic_advertising_set_info_transfer(
        acl_handle, service_data, adv_handle,
        base::Bind(&status_handle_callback, std::move(command_complete)));
  }

  void SetPeriodicAdvSyncTransferParams(const RawAddress& bd_addr, uint8_t mode,
                                        uint16_t skip, uint16_t sync_timeout,
                                        uint8_t cte_type, bool set_defaults,
                                        status_cb command_complete) override {
    uint16_t acl_handle = acl_get_hci_handle_for_hcif(bd_addr, BT_TRANSPORT_LE);

    if (acl_handle == HCI_INVALID_HANDLE) {
      LOG(ERROR) << __func__
                 << ": Wrong mode: no LE link exist or LE not supported";
      return;
    }

    if (set_defaults)
      btsnd_hcic_ble_set_default_periodic_advertising_sync_transfer_params(
          acl_handle, mode, skip, sync_timeout, cte_type,
          base::Bind(&status_callback, std::move(command_complete)));
    else
      btsnd_hcic_ble_set_periodic_advertising_sync_transfer_params(
          acl_handle, mode, skip, sync_timeout, cte_type,
          base::Bind(&status_callback, std::move(command_complete)));
  }
};

class BleScannerCompleteImpl : public BleScannerListImpl,
                               public BleScannerSyncTransferImpl {
  // Not much to do here :)
};

}  // namespace

void BleScannerHciInterface::Initialize() {
  VLOG(1) << __func__;
  LOG_ASSERT(instance == nullptr) << "Was already initialized.";

  if ((controller_get_interface()->get_ble_periodic_advertiser_list_size()) &&
      (controller_get_interface()
           ->supports_ble_periodic_advertising_sync_transfer_sender())) {
    LOG(INFO) << "Advertiser list in controller can be used";
    LOG(INFO) << "Periodic Adv Sync Transfer Sender role is supported";
    instance = new BleScannerCompleteImpl();
  } else if (controller_get_interface()
                 ->supports_ble_periodic_advertising_sync_transfer_sender()) {
    LOG(INFO) << "Periodic Adv Sync Transfer Sender role is supported";
    instance = new BleScannerSyncTransferImpl();
  } else if (controller_get_interface()
                 ->get_ble_periodic_advertiser_list_size()) {
    LOG(INFO) << "Periodic Adv Sync Transfer Recipient role is supported";
    instance = new BleScannerListImpl();
  }
  // TODO: Implement periodic adv. sync. recipient role if ever needed.
}

BleScannerHciInterface* BleScannerHciInterface::Get() { return instance; }

void BleScannerHciInterface::CleanUp() {
  VLOG(1) << __func__;

  delete instance;
  instance = nullptr;
}

void btm_ble_process_periodic_adv_sync_est_evt(uint8_t data_len,
                                               uint8_t* data) {
  uint16_t sync_handle, adv_interval;
  uint8_t status, adv_sid, adv_addr_type, adv_phy, adv_clock_accuracy;
  RawAddress adv_addr;

  VLOG(1) << __func__;

  LOG_ASSERT(data_len == 15)
      << "Malformed LE Periodic Advertising Sync Est. Event from controller";

  STREAM_TO_UINT8(status, data);
  STREAM_TO_UINT16(sync_handle, data);
  STREAM_TO_UINT8(adv_sid, data);
  STREAM_TO_UINT8(adv_addr_type, data);
  STREAM_TO_BDADDR(adv_addr, data);
  STREAM_TO_UINT8(adv_phy, data);
  STREAM_TO_UINT16(adv_interval, data);
  STREAM_TO_UINT8(adv_clock_accuracy, data);

  if (BleScannerHciInterface::Get()) {
    static_cast<BleScannerImplBase*>(BleScannerHciInterface::Get())
        ->OnPeriodicAdvSyncEstablished(status, sync_handle, adv_sid,
                                       adv_addr_type, adv_addr, adv_phy,
                                       adv_interval, adv_clock_accuracy);
  }
}

void btm_ble_process_periodic_adv_pkt(uint8_t data_len, uint8_t* data) {
  uint8_t* p = data;
  uint16_t sync_handle;
  uint8_t tx_power, cte_type, pkt_data_status, pkt_data_len;
  int8_t rssi;

  LOG_ASSERT(data_len >= 7)
      << "Malformed LE Periodic Advertising Report Event from controller";

  STREAM_TO_UINT16(sync_handle, p);
  STREAM_TO_UINT8(tx_power, p);
  STREAM_TO_INT8(rssi, p);
  STREAM_TO_UINT8(cte_type, p);
  STREAM_TO_UINT8(pkt_data_status, p);
  STREAM_TO_UINT8(pkt_data_len, p);

  uint8_t* pkt_data = p;
  p += pkt_data_len;

  if (p > data + data_len) {
    LOG(ERROR) << __func__ << " Invalid pkt_data_len: " << int{pkt_data_len};
    return;
  }

  if (rssi >= 21 && rssi <= 126) {
    LOG(ERROR) << __func__
               << " bad rssi value in advertising report: " << int{rssi};
  }

  if (BleScannerHciInterface::Get()) {
    static_cast<BleScannerImplBase*>(BleScannerHciInterface::Get())
        ->OnPeriodicScanResult(sync_handle, tx_power, rssi, cte_type,
                               pkt_data_status, pkt_data_len, pkt_data);
  }
}

void btm_ble_process_periodic_adv_sync_lost_evt(uint8_t data_len,
                                                uint8_t* data) {
  uint16_t sync_handle;

  STREAM_TO_UINT16(sync_handle, data);

  if (BleScannerHciInterface::Get()) {
    static_cast<BleScannerImplBase*>(BleScannerHciInterface::Get())
        ->OnPeriodicSyncLost(sync_handle);
  }
}
+230 −0

File added.

Preview size limit exceeded, changes collapsed.

+3 −0
Original line number Diff line number Diff line
@@ -36,6 +36,9 @@
#include "smp_api.h"

extern void btm_ble_refresh_raddr_timer_timeout(void* data);
extern void btm_ble_process_periodic_adv_sync_est_evt(uint8_t len, uint8_t* p);
extern void btm_ble_process_periodic_adv_pkt(uint8_t len, uint8_t* p);
extern void btm_ble_process_periodic_adv_sync_lost_evt(uint8_t len, uint8_t* p);
extern tBTM_STATUS btm_ble_read_remote_name(const RawAddress& remote_bda,
                                            tBTM_CMPL_CB* p_cb);
extern bool btm_ble_cancel_remote_name(const RawAddress& remote_bda);
Loading