You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1379 lines
52 KiB

/*
* Copyright 2019 The Android Open Source Project
*
* 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 <memory>
#include <mutex>
#include <set>
#include "hci/acl_manager.h"
#include "hci/controller.h"
#include "hci/hci_layer.h"
#include "hci/hci_packets.h"
#include "hci/le_scanning_interface.h"
#include "hci/le_scanning_manager.h"
#include "hci/vendor_specific_event_manager.h"
#include "module.h"
#include "os/handler.h"
#include "os/log.h"
namespace bluetooth {
namespace hci {
constexpr uint16_t kLeScanWindowMin = 0x0004;
constexpr uint16_t kLeScanWindowMax = 0x4000;
constexpr uint16_t kDefaultLeExtendedScanWindow = 4800;
constexpr uint16_t kLeExtendedScanWindowMax = 0xFFFF;
constexpr uint16_t kLeScanIntervalMin = 0x0004;
constexpr uint16_t kLeScanIntervalMax = 0x4000;
constexpr uint16_t kDefaultLeExtendedScanInterval = 4800;
constexpr uint16_t kLeExtendedScanIntervalMax = 0xFFFF;
constexpr uint8_t kScannableBit = 1;
constexpr uint8_t kDirectedBit = 2;
constexpr uint8_t kScanResponseBit = 3;
constexpr uint8_t kLegacyBit = 4;
constexpr uint8_t kDataStatusBits = 5;
const ModuleFactory LeScanningManager::Factory = ModuleFactory([]() { return new LeScanningManager(); });
enum class ScanApiType {
LEGACY = 1,
ANDROID_HCI = 2,
EXTENDED = 3,
};
struct Scanner {
Uuid app_uuid;
bool in_use;
};
class AdvertisingCache {
public:
const std::vector<uint8_t>& Set(const AddressWithType& address_with_type, std::vector<uint8_t> data) {
auto it = Find(address_with_type);
if (it != items.end()) {
it->data = std::move(data);
return it->data;
}
if (items.size() > cache_max) {
items.pop_back();
}
items.emplace_front(address_with_type, std::move(data));
return items.front().data;
}
bool Exist(const AddressWithType& address_with_type) {
auto it = Find(address_with_type);
if (it == items.end()) {
return false;
}
return true;
}
const std::vector<uint8_t>& Append(const AddressWithType& address_with_type, std::vector<uint8_t> data) {
auto it = Find(address_with_type);
if (it != items.end()) {
it->data.insert(it->data.end(), data.begin(), data.end());
return it->data;
}
if (items.size() > cache_max) {
items.pop_back();
}
items.emplace_front(address_with_type, std::move(data));
return items.front().data;
}
/* Clear data for device |addr_type, addr| */
void Clear(AddressWithType address_with_type) {
auto it = Find(address_with_type);
if (it != items.end()) {
items.erase(it);
}
}
void ClearAll() {
items.clear();
}
struct Item {
AddressWithType address_with_type;
std::vector<uint8_t> data;
Item(const AddressWithType& address_with_type, std::vector<uint8_t> data)
: address_with_type(address_with_type), data(data) {}
};
std::list<Item>::iterator Find(const AddressWithType& address_with_type) {
for (auto it = items.begin(); it != items.end(); it++) {
if (it->address_with_type == address_with_type) {
return it;
}
}
return items.end();
}
/* we keep maximum 7 devices in the cache */
const size_t cache_max = 1000;
std::list<Item> items;
};
class NullScanningCallback : public ScanningCallback {
void OnScannerRegistered(const bluetooth::hci::Uuid app_uuid, ScannerId scanner_id, ScanningStatus status) {
LOG_INFO("OnScannerRegistered in NullScanningCallback");
}
void OnScanResult(
uint16_t event_type,
uint8_t address_type,
Address address,
uint8_t primary_phy,
uint8_t secondary_phy,
uint8_t advertising_sid,
int8_t tx_power,
int8_t rssi,
uint16_t periodic_advertising_interval,
std::vector<uint8_t> advertising_data) {
LOG_INFO("OnScanResult in NullScanningCallback");
}
void OnTrackAdvFoundLost(AdvertisingFilterOnFoundOnLostInfo on_found_on_lost_info) {
LOG_INFO("OnTrackAdvFoundLost in NullScanningCallback");
}
void OnBatchScanReports(int client_if, int status, int report_format, int num_records, std::vector<uint8_t> data) {
LOG_INFO("OnBatchScanReports in NullScanningCallback");
}
void OnBatchScanThresholdCrossed(int client_if) {
LOG_INFO("OnBatchScanThresholdCrossed in NullScanningCallback");
}
void OnTimeout() {
LOG_INFO("OnTimeout in NullScanningCallback");
}
void OnFilterEnable(Enable enable, uint8_t status) {
LOG_INFO("OnFilterEnable in NullScanningCallback");
}
void OnFilterParamSetup(uint8_t available_spaces, ApcfAction action, uint8_t status) {
LOG_INFO("OnFilterParamSetup in NullScanningCallback");
}
void OnFilterConfigCallback(
ApcfFilterType filter_type, uint8_t available_spaces, ApcfAction action, uint8_t status) {
LOG_INFO("OnFilterConfigCallback in NullScanningCallback");
}
};
enum class BatchScanState {
ERROR_STATE = 0,
ENABLE_CALLED = 1,
ENABLED_STATE = 2,
DISABLE_CALLED = 3,
DISABLED_STATE = 4,
};
#define BTM_BLE_BATCH_SCAN_MODE_DISABLE 0
#define BTM_BLE_BATCH_SCAN_MODE_PASS 1
#define BTM_BLE_BATCH_SCAN_MODE_ACTI 2
#define BTM_BLE_BATCH_SCAN_MODE_PASS_ACTI 3
struct BatchScanConfig {
BatchScanState current_state;
BatchScanMode scan_mode;
uint32_t scan_interval;
uint32_t scan_window;
BatchScanDiscardRule discard_rule;
ScannerId ref_value;
};
struct LeScanningManager::impl : public bluetooth::hci::LeAddressManagerCallback {
impl(Module* module) : module_(module), le_scanning_interface_(nullptr) {}
~impl() {
if (address_manager_registered_) {
le_address_manager_->Unregister(this);
}
}
void start(
os::Handler* handler,
hci::HciLayer* hci_layer,
hci::Controller* controller,
hci::AclManager* acl_manager,
hci::VendorSpecificEventManager* vendor_specific_event_manager) {
module_handler_ = handler;
hci_layer_ = hci_layer;
controller_ = controller;
vendor_specific_event_manager_ = vendor_specific_event_manager;
le_address_manager_ = acl_manager->GetLeAddressManager();
le_scanning_interface_ = hci_layer_->GetLeScanningInterface(
module_handler_->BindOn(this, &LeScanningManager::impl::handle_scan_results));
if (controller_->IsSupported(OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS)) {
api_type_ = ScanApiType::EXTENDED;
interval_ms_ = kDefaultLeExtendedScanInterval;
window_ms_ = kDefaultLeExtendedScanWindow;
} else if (controller_->IsSupported(OpCode::LE_EXTENDED_SCAN_PARAMS)) {
api_type_ = ScanApiType::ANDROID_HCI;
} else {
api_type_ = ScanApiType::LEGACY;
}
is_filter_support_ = controller_->IsSupported(OpCode::LE_ADV_FILTER);
is_batch_scan_support_ = controller->IsSupported(OpCode::LE_BATCH_SCAN);
if (is_batch_scan_support_) {
vendor_specific_event_manager_->RegisterEventHandler(
VseSubeventCode::BLE_THRESHOLD, handler->BindOn(this, &LeScanningManager::impl::on_storage_threshold_breach));
vendor_specific_event_manager_->RegisterEventHandler(
VseSubeventCode::BLE_TRACKING, handler->BindOn(this, &LeScanningManager::impl::on_advertisement_tracking));
}
scanners_ = std::vector<Scanner>(kMaxAppNum + 1);
for (size_t i = 0; i < scanners_.size(); i++) {
scanners_[i].app_uuid = Uuid::kEmpty;
scanners_[i].in_use = false;
}
batch_scan_config_.current_state = BatchScanState::DISABLED_STATE;
batch_scan_config_.ref_value = kInvalidScannerId;
configure_scan();
}
void stop() {
for (auto subevent_code : LeScanningEvents) {
hci_layer_->UnregisterLeEventHandler(subevent_code);
}
if (is_batch_scan_support_) {
// TODO implete vse module
// hci_layer_->UnregisterVesEventHandler(VseSubeventCode::BLE_THRESHOLD);
// hci_layer_->UnregisterVesEventHandler(VseSubeventCode::BLE_TRACKING);
}
batch_scan_config_.current_state = BatchScanState::DISABLED_STATE;
batch_scan_config_.ref_value = kInvalidScannerId;
scanning_callbacks_ = &null_scanning_callback_;
}
void handle_scan_results(LeMetaEventView event) {
switch (event.GetSubeventCode()) {
case hci::SubeventCode::ADVERTISING_REPORT:
handle_advertising_report(LeAdvertisingReportView::Create(event));
break;
case hci::SubeventCode::DIRECTED_ADVERTISING_REPORT:
handle_directed_advertising_report(LeDirectedAdvertisingReportView::Create(event));
break;
case hci::SubeventCode::EXTENDED_ADVERTISING_REPORT:
handle_extended_advertising_report(LeExtendedAdvertisingReportView::Create(event));
break;
case hci::SubeventCode::SCAN_TIMEOUT:
scanning_callbacks_->OnTimeout();
break;
default:
LOG_ALWAYS_FATAL("Unknown advertising subevent %s", hci::SubeventCodeText(event.GetSubeventCode()).c_str());
}
}
struct ExtendedEventTypeOptions {
bool connectable{false};
bool scannable{false};
bool directed{false};
bool scan_response{false};
bool legacy{false};
bool continuing{false};
bool truncated{false};
};
void transform_to_extended_event_type(uint16_t* extended_event_type, ExtendedEventTypeOptions o) {
ASSERT(extended_event_type != nullptr);
*extended_event_type = (o.connectable ? 0x0001 << 0 : 0) | (o.scannable ? 0x0001 << 1 : 0) |
(o.directed ? 0x0001 << 2 : 0) | (o.scan_response ? 0x0001 << 3 : 0) |
(o.legacy ? 0x0001 << 4 : 0) | (o.continuing ? 0x0001 << 5 : 0) |
(o.truncated ? 0x0001 << 6 : 0);
}
void handle_advertising_report(LeAdvertisingReportView event_view) {
if (!event_view.IsValid()) {
LOG_INFO("Dropping invalid advertising event");
return;
}
std::vector<LeAdvertisingReport> reports = event_view.GetAdvertisingReports();
if (reports.empty()) {
LOG_INFO("Zero results in advertising event");
return;
}
for (LeAdvertisingReport report : reports) {
uint16_t extended_event_type = 0;
switch (report.event_type_) {
case hci::AdvertisingEventType::ADV_IND:
transform_to_extended_event_type(
&extended_event_type, {.connectable = true, .scannable = true, .legacy = true});
break;
case hci::AdvertisingEventType::ADV_DIRECT_IND:
transform_to_extended_event_type(
&extended_event_type, {.connectable = true, .directed = true, .legacy = true});
break;
case hci::AdvertisingEventType::ADV_SCAN_IND:
transform_to_extended_event_type(&extended_event_type, {.scannable = true, .legacy = true});
break;
case hci::AdvertisingEventType::ADV_NONCONN_IND:
transform_to_extended_event_type(&extended_event_type, {.legacy = true});
break;
case hci::AdvertisingEventType::SCAN_RESPONSE:
transform_to_extended_event_type(
&extended_event_type, {.connectable = true, .scannable = true, .scan_response = true, .legacy = true});
break;
default:
LOG_WARN("Unsupported event type:%d", (uint16_t)report.event_type_);
return;
}
std::vector<uint8_t> advertising_data = {};
for (auto gap_data : report.advertising_data_) {
advertising_data.push_back((uint8_t)gap_data.size() - 1);
advertising_data.push_back((uint8_t)gap_data.data_type_);
advertising_data.insert(advertising_data.end(), gap_data.data_.begin(), gap_data.data_.end());
}
process_advertising_package_content(
extended_event_type,
(uint8_t)report.address_type_,
report.address_,
(uint8_t)PrimaryPhyType::LE_1M,
(uint8_t)SecondaryPhyType::NO_PACKETS,
kAdvertisingDataInfoNotPresent,
kTxPowerInformationNotPresent,
report.rssi_,
kNotPeriodicAdvertisement,
advertising_data);
}
}
void handle_directed_advertising_report(LeDirectedAdvertisingReportView event_view) {
if (!event_view.IsValid()) {
LOG_INFO("Dropping invalid advertising event");
return;
}
std::vector<LeDirectedAdvertisingReport> reports = event_view.GetAdvertisingReports();
if (reports.empty()) {
LOG_INFO("Zero results in advertising event");
return;
}
uint16_t extended_event_type = 0;
transform_to_extended_event_type(&extended_event_type, {.connectable = true, .directed = true, .legacy = true});
// TODO: parse report
}
void handle_extended_advertising_report(LeExtendedAdvertisingReportView event_view) {
if (!event_view.IsValid()) {
LOG_INFO("Dropping invalid advertising event");
return;
}
std::vector<LeExtendedAdvertisingReport> reports = event_view.GetAdvertisingReports();
if (reports.empty()) {
LOG_INFO("Zero results in advertising event");
return;
}
for (LeExtendedAdvertisingReport report : reports) {
uint16_t event_type = report.connectable_ | (report.scannable_ << kScannableBit) |
(report.directed_ << kDirectedBit) | (report.scan_response_ << kScanResponseBit) |
(report.legacy_ << kLegacyBit) | ((uint16_t)report.data_status_ << kDataStatusBits);
process_advertising_package_content(
event_type,
(uint8_t)report.address_type_,
report.address_,
(uint8_t)report.primary_phy_,
(uint8_t)report.secondary_phy_,
report.advertising_sid_,
report.tx_power_,
report.rssi_,
report.periodic_advertising_interval_,
report.advertising_data_);
}
}
void process_advertising_package_content(
uint16_t event_type,
uint8_t address_type,
Address address,
uint8_t primary_phy,
uint8_t secondary_phy,
uint8_t advertising_sid,
int8_t tx_power,
int8_t rssi,
uint16_t periodic_advertising_interval,
std::vector<uint8_t> advertising_data) {
bool is_scannable = event_type & (1 << kScannableBit);
bool is_scan_response = event_type & (1 << kScanResponseBit);
bool is_legacy = event_type & (1 << kLegacyBit);
if (address_type == (uint8_t)DirectAdvertisingAddressType::NO_ADDRESS) {
scanning_callbacks_->OnScanResult(
event_type,
address_type,
address,
primary_phy,
secondary_phy,
advertising_sid,
tx_power,
rssi,
periodic_advertising_interval,
advertising_data);
return;
} else if (address == Address::kEmpty) {
LOG_WARN("Receive non-anonymous advertising report with empty address, skip!");
return;
}
AddressWithType address_with_type(address, (AddressType)address_type);
if (is_legacy && is_scan_response && !advertising_cache_.Exist(address_with_type)) {
return;
}
bool is_start = is_legacy && is_scannable && !is_scan_response;
std::vector<uint8_t> const& adv_data = is_start ? advertising_cache_.Set(address_with_type, advertising_data)
: advertising_cache_.Append(address_with_type, advertising_data);
uint8_t data_status = event_type >> kDataStatusBits;
if (data_status == (uint8_t)DataStatus::CONTINUING) {
// Waiting for whole data
return;
}
if (is_scannable && !is_scan_response) {
// Waiting for scan response
return;
}
scanning_callbacks_->OnScanResult(
event_type,
address_type,
address,
primary_phy,
secondary_phy,
advertising_sid,
tx_power,
rssi,
periodic_advertising_interval,
adv_data);
advertising_cache_.Clear(address_with_type);
}
void configure_scan() {
std::vector<PhyScanParameters> parameter_vector;
PhyScanParameters phy_scan_parameters;
phy_scan_parameters.le_scan_window_ = window_ms_;
phy_scan_parameters.le_scan_interval_ = interval_ms_;
phy_scan_parameters.le_scan_type_ = le_scan_type_;
parameter_vector.push_back(phy_scan_parameters);
uint8_t phys_in_use = 1;
// The Host shall not issue set scan parameter command when scanning is enabled
stop_scan();
if (le_address_manager_->GetAddressPolicy() != LeAddressManager::USE_PUBLIC_ADDRESS) {
own_address_type_ = OwnAddressType::RANDOM_DEVICE_ADDRESS;
}
switch (api_type_) {
case ScanApiType::EXTENDED:
le_scanning_interface_->EnqueueCommand(hci::LeSetExtendedScanParametersBuilder::Create(
own_address_type_, filter_policy_, phys_in_use, parameter_vector),
module_handler_->BindOnce(impl::check_status));
break;
case ScanApiType::ANDROID_HCI:
le_scanning_interface_->EnqueueCommand(
hci::LeExtendedScanParamsBuilder::Create(LeScanType::ACTIVE, interval_ms_, window_ms_, own_address_type_,
filter_policy_),
module_handler_->BindOnce(impl::check_status));
break;
case ScanApiType::LEGACY:
le_scanning_interface_->EnqueueCommand(
hci::LeSetScanParametersBuilder::Create(LeScanType::ACTIVE, interval_ms_, window_ms_, own_address_type_,
filter_policy_),
module_handler_->BindOnce(impl::check_status));
break;
}
}
void register_scanner(const Uuid app_uuid) {
for (uint8_t i = 1; i <= kMaxAppNum; i++) {
if (scanners_[i].in_use && scanners_[i].app_uuid == app_uuid) {
LOG_ERROR("Application already registered %s", app_uuid.ToString().c_str());
scanning_callbacks_->OnScannerRegistered(app_uuid, 0x00, ScanningCallback::ScanningStatus::INTERNAL_ERROR);
return;
}
}
// valid value of scanner id : 1 ~ kMaxAppNum
for (uint8_t i = 1; i <= kMaxAppNum; i++) {
if (!scanners_[i].in_use) {
scanners_[i].app_uuid = app_uuid;
scanners_[i].in_use = true;
scanning_callbacks_->OnScannerRegistered(app_uuid, i, ScanningCallback::ScanningStatus::SUCCESS);
return;
}
}
LOG_ERROR("Unable to register scanner, max client reached:%d", kMaxAppNum);
scanning_callbacks_->OnScannerRegistered(app_uuid, 0x00, ScanningCallback::ScanningStatus::NO_RESOURCES);
}
void unregister_scanner(ScannerId scanner_id) {
if (scanner_id <= 0 || scanner_id > kMaxAppNum) {
LOG_WARN("Invalid scanner id");
return;
}
if (scanners_[scanner_id].in_use) {
scanners_[scanner_id].in_use = false;
scanners_[scanner_id].app_uuid = Uuid::kEmpty;
} else {
LOG_WARN("Unregister scanner with unused scanner id");
}
}
void scan(bool start) {
if (start) {
configure_scan();
start_scan();
} else {
if (address_manager_registered_) {
le_address_manager_->Unregister(this);
address_manager_registered_ = false;
}
stop_scan();
}
}
void start_scan() {
// If we receive start_scan during paused, set scan_on_resume_ to true
if (paused_) {
scan_on_resume_ = true;
return;
}
is_scanning_ = true;
if (!address_manager_registered_) {
le_address_manager_->Register(this);
address_manager_registered_ = true;
}
switch (api_type_) {
case ScanApiType::EXTENDED:
le_scanning_interface_->EnqueueCommand(
hci::LeSetExtendedScanEnableBuilder::Create(
Enable::ENABLED, FilterDuplicates::DISABLED /* filter duplicates */, 0, 0),
module_handler_->BindOnce(impl::check_status));
break;
case ScanApiType::ANDROID_HCI:
case ScanApiType::LEGACY:
le_scanning_interface_->EnqueueCommand(
hci::LeSetScanEnableBuilder::Create(Enable::ENABLED, Enable::DISABLED /* filter duplicates */),
module_handler_->BindOnce(impl::check_status));
break;
}
}
void stop_scan() {
is_scanning_ = false;
switch (api_type_) {
case ScanApiType::EXTENDED:
le_scanning_interface_->EnqueueCommand(
hci::LeSetExtendedScanEnableBuilder::Create(
Enable::DISABLED, FilterDuplicates::DISABLED /* filter duplicates */, 0, 0),
module_handler_->BindOnce(impl::check_status));
break;
case ScanApiType::ANDROID_HCI:
case ScanApiType::LEGACY:
le_scanning_interface_->EnqueueCommand(
hci::LeSetScanEnableBuilder::Create(Enable::DISABLED, Enable::DISABLED /* filter duplicates */),
module_handler_->BindOnce(impl::check_status));
break;
}
}
void set_scan_parameters(LeScanType scan_type, uint16_t scan_interval, uint16_t scan_window) {
uint32_t max_scan_interval = kLeScanIntervalMax;
uint32_t max_scan_window = kLeScanWindowMax;
if (api_type_ == ScanApiType::EXTENDED) {
max_scan_interval = kLeExtendedScanIntervalMax;
max_scan_window = kLeExtendedScanWindowMax;
}
if (scan_type != LeScanType::ACTIVE && scan_type != LeScanType::PASSIVE) {
LOG_ERROR("Invalid scan type");
return;
}
if (scan_interval > max_scan_interval || scan_interval < kLeScanIntervalMin) {
LOG_ERROR("Invalid scan_interval %d", scan_interval);
return;
}
if (scan_window > max_scan_window || scan_window < kLeScanWindowMin) {
LOG_ERROR("Invalid scan_window %d", scan_window);
return;
}
le_scan_type_ = scan_type;
interval_ms_ = scan_interval;
window_ms_ = scan_window;
}
void scan_filter_enable(bool enable) {
if (!is_filter_support_) {
LOG_WARN("Advertising filter is not supported");
return;
}
Enable apcf_enable = enable ? Enable::ENABLED : Enable::DISABLED;
le_scanning_interface_->EnqueueCommand(
LeAdvFilterEnableBuilder::Create(apcf_enable),
module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete));
}
void scan_filter_parameter_setup(
ApcfAction action, uint8_t filter_index, AdvertisingFilterParameter advertising_filter_parameter) {
if (!is_filter_support_) {
LOG_WARN("Advertising filter is not supported");
return;
}
switch (action) {
case ApcfAction::ADD:
le_scanning_interface_->EnqueueCommand(
LeAdvFilterAddFilteringParametersBuilder::Create(
filter_index,
advertising_filter_parameter.feature_selection,
advertising_filter_parameter.list_logic_type,
advertising_filter_parameter.filter_logic_type,
advertising_filter_parameter.rssi_high_thresh,
advertising_filter_parameter.delivery_mode,
advertising_filter_parameter.onfound_timeout,
advertising_filter_parameter.onfound_timeout_cnt,
advertising_filter_parameter.rssi_low_thres,
advertising_filter_parameter.onlost_timeout,
advertising_filter_parameter.num_of_tracking_entries),
module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete));
break;
case ApcfAction::DELETE:
le_scanning_interface_->EnqueueCommand(
LeAdvFilterDeleteFilteringParametersBuilder::Create(filter_index),
module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete));
break;
case ApcfAction::CLEAR:
le_scanning_interface_->EnqueueCommand(
LeAdvFilterClearFilteringParametersBuilder::Create(),
module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete));
break;
default:
LOG_ERROR("Unknown action type: %d", (uint16_t)action);
break;
}
}
void scan_filter_add(uint8_t filter_index, std::vector<AdvertisingPacketContentFilterCommand> filters) {
if (!is_filter_support_) {
LOG_WARN("Advertising filter is not supported");
return;
}
ApcfAction apcf_action = ApcfAction::ADD;
for (auto filter : filters) {
/* If data is passed, both mask and data have to be the same length */
if (filter.data.size() != filter.data_mask.size() && filter.data.size() != 0 && filter.data_mask.size() != 0) {
LOG_ERROR("data and data_mask are of different size");
continue;
}
switch (filter.filter_type) {
case ApcfFilterType::BROADCASTER_ADDRESS: {
update_address_filter(apcf_action, filter_index, filter.address, filter.application_address_type);
break;
}
case ApcfFilterType::SERVICE_UUID:
case ApcfFilterType::SERVICE_SOLICITATION_UUID: {
update_uuid_filter(apcf_action, filter_index, filter.filter_type, filter.uuid, filter.uuid_mask);
break;
}
case ApcfFilterType::LOCAL_NAME: {
update_local_name_filter(apcf_action, filter_index, filter.name);
break;
}
case ApcfFilterType::MANUFACTURER_DATA: {
update_manufacturer_data_filter(
apcf_action, filter_index, filter.company, filter.company_mask, filter.data, filter.data_mask);
break;
}
case ApcfFilterType::SERVICE_DATA: {
update_service_data_filter(apcf_action, filter_index, filter.data, filter.data_mask);
break;
}
default:
LOG_ERROR("Unknown filter type: %d", (uint16_t)filter.filter_type);
break;
}
}
}
void update_address_filter(
ApcfAction action, uint8_t filter_index, Address address, ApcfApplicationAddressType address_type) {
if (action != ApcfAction::CLEAR) {
le_scanning_interface_->EnqueueCommand(
LeAdvFilterBroadcasterAddressBuilder::Create(action, filter_index, address, address_type),
module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete));
} else {
le_scanning_interface_->EnqueueCommand(
LeAdvFilterClearBroadcasterAddressBuilder::Create(filter_index),
module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete));
}
}
void update_uuid_filter(
ApcfAction action, uint8_t filter_index, ApcfFilterType filter_type, Uuid uuid, Uuid uuid_mask) {
std::vector<uint8_t> combined_data = {};
if (action != ApcfAction::CLEAR) {
uint8_t uuid_len = uuid.GetShortestRepresentationSize();
if (uuid_len == Uuid::kNumBytes16) {
uint16_t data = uuid.As16Bit();
combined_data.push_back((uint8_t)data);
combined_data.push_back((uint8_t)(data >> 8));
} else if (uuid_len == Uuid::kNumBytes32) {
uint16_t data = uuid.As32Bit();
combined_data.push_back((uint8_t)data);
combined_data.push_back((uint8_t)(data >> 8));
combined_data.push_back((uint8_t)(data >> 16));
combined_data.push_back((uint8_t)(data >> 24));
} else if (uuid_len == Uuid::kNumBytes128) {
auto data = uuid.To128BitLE();
combined_data.insert(combined_data.end(), data.begin(), data.end());
} else {
LOG_ERROR("illegal UUID length: %d", (uint16_t)uuid_len);
return;
}
if (!uuid_mask.IsEmpty()) {
if (uuid_len == Uuid::kNumBytes16) {
uint16_t data = uuid_mask.As16Bit();
combined_data.push_back((uint8_t)data);
combined_data.push_back((uint8_t)(data >> 8));
} else if (uuid_len == Uuid::kNumBytes32) {
uint16_t data = uuid_mask.As32Bit();
combined_data.push_back((uint8_t)data);
combined_data.push_back((uint8_t)(data >> 8));
combined_data.push_back((uint8_t)(data >> 16));
combined_data.push_back((uint8_t)(data >> 24));
} else if (uuid_len == Uuid::kNumBytes128) {
auto data = uuid_mask.To128BitLE();
combined_data.insert(combined_data.end(), data.begin(), data.end());
}
} else {
std::vector<uint8_t> data(uuid_len, 0xFF);
combined_data.insert(combined_data.end(), data.begin(), data.end());
}
}
if (filter_type == ApcfFilterType::SERVICE_UUID) {
le_scanning_interface_->EnqueueCommand(
LeAdvFilterServiceUuidBuilder::Create(action, filter_index, combined_data),
module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete));
} else {
le_scanning_interface_->EnqueueCommand(
LeAdvFilterSolicitationUuidBuilder::Create(action, filter_index, combined_data),
module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete));
}
}
void update_local_name_filter(ApcfAction action, uint8_t filter_index, std::vector<uint8_t> name) {
le_scanning_interface_->EnqueueCommand(
LeAdvFilterLocalNameBuilder::Create(action, filter_index, name),
module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete));
}
void update_manufacturer_data_filter(
ApcfAction action,
uint8_t filter_index,
uint16_t company_id,
uint16_t company_id_mask,
std::vector<uint8_t> data,
std::vector<uint8_t> data_mask) {
if (data.size() != data_mask.size()) {
LOG_ERROR("manufacturer data mask should have the same length as manufacturer data");
return;
}
std::vector<uint8_t> combined_data = {};
if (action != ApcfAction::CLEAR) {
combined_data.push_back((uint8_t)company_id);
combined_data.push_back((uint8_t)(company_id >> 8));
if (data.size() != 0) {
combined_data.insert(combined_data.end(), data.begin(), data.end());
}
if (company_id_mask != 0) {
combined_data.push_back((uint8_t)company_id_mask);
combined_data.push_back((uint8_t)(company_id_mask >> 8));
} else {
combined_data.push_back(0xFF);
combined_data.push_back(0xFF);
}
if (data_mask.size() != 0) {
combined_data.insert(combined_data.end(), data_mask.begin(), data_mask.end());
}
}
le_scanning_interface_->EnqueueCommand(
LeAdvFilterManufacturerDataBuilder::Create(action, filter_index, combined_data),
module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete));
}
void update_service_data_filter(
ApcfAction action, uint8_t filter_index, std::vector<uint8_t> data, std::vector<uint8_t> data_mask) {
if (data.size() != data_mask.size()) {
LOG_ERROR("service data mask should have the same length as service data");
return;
}
std::vector<uint8_t> combined_data = {};
if (action != ApcfAction::CLEAR && data.size() != 0) {
combined_data.insert(combined_data.end(), data.begin(), data.end());
combined_data.insert(combined_data.end(), data_mask.begin(), data_mask.end());
}
le_scanning_interface_->EnqueueCommand(
LeAdvFilterServiceDataBuilder::Create(action, filter_index, combined_data),
module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete));
}
void batch_scan_set_storage_parameter(
uint8_t batch_scan_full_max,
uint8_t batch_scan_truncated_max,
uint8_t batch_scan_notify_threshold,
ScannerId scanner_id) {
if (!is_batch_scan_support_) {
LOG_WARN("Batch scan is not supported");
return;
}
// scanner id for OnBatchScanThresholdCrossed
batch_scan_config_.ref_value = scanner_id;
if (batch_scan_config_.current_state == BatchScanState::ERROR_STATE ||
batch_scan_config_.current_state == BatchScanState::DISABLED_STATE ||
batch_scan_config_.current_state == BatchScanState::DISABLE_CALLED) {
batch_scan_config_.current_state = BatchScanState::ENABLE_CALLED;
le_scanning_interface_->EnqueueCommand(
LeBatchScanEnableBuilder::Create(Enable::ENABLED),
module_handler_->BindOnceOn(this, &impl::on_batch_scan_enable_complete));
}
le_scanning_interface_->EnqueueCommand(
LeBatchScanSetStorageParametersBuilder::Create(
batch_scan_full_max, batch_scan_truncated_max, batch_scan_notify_threshold),
module_handler_->BindOnceOn(this, &impl::on_batch_scan_complete));
}
void batch_scan_enable(
BatchScanMode scan_mode,
uint32_t duty_cycle_scan_window_slots,
uint32_t duty_cycle_scan_interval_slots,
BatchScanDiscardRule batch_scan_discard_rule) {
if (!is_batch_scan_support_) {
LOG_WARN("Batch scan is not supported");
return;
}
if (batch_scan_config_.current_state == BatchScanState::ERROR_STATE ||
batch_scan_config_.current_state == BatchScanState::DISABLED_STATE ||
batch_scan_config_.current_state == BatchScanState::DISABLE_CALLED) {
batch_scan_config_.current_state = BatchScanState::ENABLE_CALLED;
le_scanning_interface_->EnqueueCommand(
LeBatchScanEnableBuilder::Create(Enable::ENABLED),
module_handler_->BindOnceOn(this, &impl::on_batch_scan_enable_complete));
}
batch_scan_config_.scan_mode = scan_mode;
batch_scan_config_.scan_interval = duty_cycle_scan_interval_slots;
batch_scan_config_.scan_window = duty_cycle_scan_window_slots;
batch_scan_config_.discard_rule = batch_scan_discard_rule;
/* This command starts batch scanning, if enabled */
batch_scan_set_scan_parameter(
scan_mode, duty_cycle_scan_window_slots, duty_cycle_scan_interval_slots, batch_scan_discard_rule);
}
void batch_scan_disable() {
if (!is_batch_scan_support_) {
LOG_WARN("Batch scan is not supported");
return;
}
batch_scan_config_.current_state = BatchScanState::DISABLE_CALLED;
batch_scan_set_scan_parameter(
BatchScanMode::DISABLE,
batch_scan_config_.scan_window,
batch_scan_config_.scan_interval,
batch_scan_config_.discard_rule);
}
void batch_scan_set_scan_parameter(
BatchScanMode scan_mode,
uint32_t duty_cycle_scan_window_slots,
uint32_t duty_cycle_scan_interval_slots,
BatchScanDiscardRule batch_scan_discard_rule) {
if (!is_batch_scan_support_) {
LOG_WARN("Batch scan is not supported");
return;
}
AdvertisingAddressType own_address_type = AdvertisingAddressType::PUBLIC_ADDRESS;
if (own_address_type_ == OwnAddressType::RANDOM_DEVICE_ADDRESS ||
own_address_type_ == OwnAddressType::RESOLVABLE_OR_RANDOM_ADDRESS) {
own_address_type = AdvertisingAddressType::RANDOM_ADDRESS;
}
uint8_t truncated_mode_enabled = 0x00;
uint8_t full_mode_enabled = 0x00;
if (scan_mode == BatchScanMode::TRUNCATED || scan_mode == BatchScanMode::TRUNCATED_AND_FULL) {
truncated_mode_enabled = 0x01;
}
if (scan_mode == BatchScanMode::FULL || scan_mode == BatchScanMode::TRUNCATED_AND_FULL) {
full_mode_enabled = 0x01;
}
if (scan_mode == BatchScanMode::DISABLE) {
le_scanning_interface_->EnqueueCommand(
LeBatchScanSetScanParametersBuilder::Create(
truncated_mode_enabled,
full_mode_enabled,
duty_cycle_scan_window_slots,
duty_cycle_scan_interval_slots,
own_address_type,
batch_scan_discard_rule),
module_handler_->BindOnceOn(this, &impl::on_batch_scan_disable_complete));
} else {
le_scanning_interface_->EnqueueCommand(
LeBatchScanSetScanParametersBuilder::Create(
truncated_mode_enabled,
full_mode_enabled,
duty_cycle_scan_window_slots,
duty_cycle_scan_interval_slots,
own_address_type,
batch_scan_discard_rule),
module_handler_->BindOnceOn(this, &impl::on_batch_scan_complete));
}
}
void batch_scan_read_results(ScannerId scanner_id, uint16_t total_num_of_records, BatchScanMode scan_mode) {
if (!is_batch_scan_support_) {
LOG_WARN("Batch scan is not supported");
int status = static_cast<int>(ErrorCode::UNSUPORTED_FEATURE_OR_PARAMETER_VALUE);
scanning_callbacks_->OnBatchScanReports(scanner_id, status, 0, 0, {});
return;
}
if (scan_mode != BatchScanMode::FULL && scan_mode != BatchScanMode::TRUNCATED) {
LOG_WARN("Invalid scan mode %d", (uint16_t)scan_mode);
int status = static_cast<int>(ErrorCode::INVALID_HCI_COMMAND_PARAMETERS);
scanning_callbacks_->OnBatchScanReports(scanner_id, status, 0, 0, {});
return;
}
if (batch_scan_result_cache_.find(scanner_id) == batch_scan_result_cache_.end()) {
std::vector<uint8_t> empty_data = {};
batch_scan_result_cache_.emplace(scanner_id, empty_data);
}
le_scanning_interface_->EnqueueCommand(
LeBatchScanReadResultParametersBuilder::Create(static_cast<BatchScanDataRead>(scan_mode)),
module_handler_->BindOnceOn(this, &impl::on_batch_scan_read_result_complete, scanner_id, total_num_of_records));
}
void track_advertiser(ScannerId scanner_id) {
if (!is_batch_scan_support_) {
LOG_WARN("Batch scan is not supported");
AdvertisingFilterOnFoundOnLostInfo on_found_on_lost_info = {};
on_found_on_lost_info.scanner_id = scanner_id;
on_found_on_lost_info.advertiser_info_present = AdvtInfoPresent::NO_ADVT_INFO_PRESENT;
scanning_callbacks_->OnTrackAdvFoundLost(on_found_on_lost_info);
return;
}
tracker_id = scanner_id;
}
void register_scanning_callback(ScanningCallback* scanning_callbacks) {
scanning_callbacks_ = scanning_callbacks;
}
void on_advertising_filter_complete(CommandCompleteView view) {
ASSERT(view.IsValid());
auto status_view = LeAdvFilterCompleteView::Create(view);
ASSERT(status_view.IsValid());
if (status_view.GetStatus() != ErrorCode::SUCCESS) {
LOG_INFO(
"Got a Command complete %s, status %s",
OpCodeText(view.GetCommandOpCode()).c_str(),
ErrorCodeText(status_view.GetStatus()).c_str());
}
ApcfOpcode apcf_opcode = status_view.GetApcfOpcode();
switch (apcf_opcode) {
case ApcfOpcode::ENABLE: {
auto complete_view = LeAdvFilterEnableCompleteView::Create(status_view);
ASSERT(complete_view.IsValid());
scanning_callbacks_->OnFilterEnable(complete_view.GetApcfEnable(), (uint8_t)complete_view.GetStatus());
} break;
case ApcfOpcode::SET_FILTERING_PARAMETERS: {
auto complete_view = LeAdvFilterSetFilteringParametersCompleteView::Create(status_view);
ASSERT(complete_view.IsValid());
scanning_callbacks_->OnFilterParamSetup(
complete_view.GetApcfAvailableSpaces(), complete_view.GetApcfAction(), (uint8_t)complete_view.GetStatus());
} break;
case ApcfOpcode::BROADCASTER_ADDRESS: {
auto complete_view = LeAdvFilterBroadcasterAddressCompleteView::Create(status_view);
ASSERT(complete_view.IsValid());
scanning_callbacks_->OnFilterConfigCallback(
ApcfFilterType::BROADCASTER_ADDRESS,
complete_view.GetApcfAvailableSpaces(),
complete_view.GetApcfAction(),
(uint8_t)complete_view.GetStatus());
} break;
case ApcfOpcode::SERVICE_UUID: {
auto complete_view = LeAdvFilterServiceUuidCompleteView::Create(status_view);
ASSERT(complete_view.IsValid());
scanning_callbacks_->OnFilterConfigCallback(
ApcfFilterType::SERVICE_UUID,
complete_view.GetApcfAvailableSpaces(),
complete_view.GetApcfAction(),
(uint8_t)complete_view.GetStatus());
} break;
case ApcfOpcode::SERVICE_SOLICITATION_UUID: {
auto complete_view = LeAdvFilterSolicitationUuidCompleteView::Create(status_view);
ASSERT(complete_view.IsValid());
scanning_callbacks_->OnFilterConfigCallback(
ApcfFilterType::SERVICE_SOLICITATION_UUID,
complete_view.GetApcfAvailableSpaces(),
complete_view.GetApcfAction(),
(uint8_t)complete_view.GetStatus());
} break;
case ApcfOpcode::LOCAL_NAME: {
auto complete_view = LeAdvFilterLocalNameCompleteView::Create(status_view);
ASSERT(complete_view.IsValid());
scanning_callbacks_->OnFilterConfigCallback(
ApcfFilterType::LOCAL_NAME,
complete_view.GetApcfAvailableSpaces(),
complete_view.GetApcfAction(),
(uint8_t)complete_view.GetStatus());
} break;
case ApcfOpcode::MANUFACTURER_DATA: {
auto complete_view = LeAdvFilterManufacturerDataCompleteView::Create(status_view);
ASSERT(complete_view.IsValid());
scanning_callbacks_->OnFilterConfigCallback(
ApcfFilterType::MANUFACTURER_DATA,
complete_view.GetApcfAvailableSpaces(),
complete_view.GetApcfAction(),
(uint8_t)complete_view.GetStatus());
} break;
case ApcfOpcode::SERVICE_DATA: {
auto complete_view = LeAdvFilterServiceDataCompleteView::Create(status_view);
ASSERT(complete_view.IsValid());
scanning_callbacks_->OnFilterConfigCallback(
ApcfFilterType::SERVICE_DATA,
complete_view.GetApcfAvailableSpaces(),
complete_view.GetApcfAction(),
(uint8_t)complete_view.GetStatus());
} break;
default:
LOG_WARN("Unexpected event type %s", OpCodeText(view.GetCommandOpCode()).c_str());
}
}
void on_batch_scan_complete(CommandCompleteView view) {
ASSERT(view.IsValid());
auto status_view = LeBatchScanCompleteView::Create(view);
ASSERT(status_view.IsValid());
if (status_view.GetStatus() != ErrorCode::SUCCESS) {
LOG_INFO(
"Got a Command complete %s, status %s, batch_scan_opcode %s",
OpCodeText(view.GetCommandOpCode()).c_str(),
ErrorCodeText(status_view.GetStatus()).c_str(),
BatchScanOpcodeText(status_view.GetBatchScanOpcode()).c_str());
}
}
void on_batch_scan_enable_complete(CommandCompleteView view) {
ASSERT(view.IsValid());
auto status_view = LeBatchScanCompleteView::Create(view);
ASSERT(status_view.IsValid());
auto complete_view = LeBatchScanEnableCompleteView::Create(status_view);
ASSERT(complete_view.IsValid());
if (status_view.GetStatus() != ErrorCode::SUCCESS) {
LOG_INFO("Got batch scan enable complete, status %s", ErrorCodeText(status_view.GetStatus()).c_str());
batch_scan_config_.current_state = BatchScanState::ERROR_STATE;
} else {
batch_scan_config_.current_state = BatchScanState::ENABLED_STATE;
}
}
void on_batch_scan_disable_complete(CommandCompleteView view) {
ASSERT(view.IsValid());
auto status_view = LeBatchScanCompleteView::Create(view);
ASSERT(status_view.IsValid());
auto complete_view = LeBatchScanSetScanParametersCompleteView::Create(status_view);
ASSERT(complete_view.IsValid());
ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS);
batch_scan_config_.current_state = BatchScanState::DISABLED_STATE;
}
void on_batch_scan_read_result_complete(
ScannerId scanner_id, uint16_t total_num_of_records, CommandCompleteView view) {
ASSERT(view.IsValid());
auto status_view = LeBatchScanCompleteView::Create(view);
ASSERT(status_view.IsValid());
auto complete_view = LeBatchScanReadResultParametersCompleteRawView::Create(status_view);
ASSERT(complete_view.IsValid());
if (complete_view.GetStatus() != ErrorCode::SUCCESS) {
LOG_INFO("Got batch scan read result complete, status %s", ErrorCodeText(status_view.GetStatus()).c_str());
}
uint8_t num_of_records = complete_view.GetNumOfRecords();
auto report_format = complete_view.GetBatchScanDataRead();
if (num_of_records == 0) {
scanning_callbacks_->OnBatchScanReports(
scanner_id, 0x00, (int)report_format, total_num_of_records, batch_scan_result_cache_[scanner_id]);
batch_scan_result_cache_.erase(scanner_id);
} else {
auto raw_data = complete_view.GetRawData();
batch_scan_result_cache_[scanner_id].insert(
batch_scan_result_cache_[scanner_id].end(), raw_data.begin(), raw_data.end());
total_num_of_records += num_of_records;
batch_scan_read_results(scanner_id, total_num_of_records, static_cast<BatchScanMode>(report_format));
}
}
void on_storage_threshold_breach(VendorSpecificEventView event) {
if (batch_scan_config_.ref_value == kInvalidScannerId) {
LOG_WARN("storage threshold was not set !!");
return;
}
scanning_callbacks_->OnBatchScanThresholdCrossed(static_cast<int>(batch_scan_config_.ref_value));
}
void on_advertisement_tracking(VendorSpecificEventView event) {
if (tracker_id == kInvalidScannerId) {
LOG_WARN("Advertisement track is not register");
return;
}
auto view = LEAdvertisementTrackingEventView::Create(event);
ASSERT(view.IsValid());
AdvertisingFilterOnFoundOnLostInfo on_found_on_lost_info = {};
on_found_on_lost_info.scanner_id = tracker_id;
on_found_on_lost_info.filter_index = view.GetApcfFilterIndex();
on_found_on_lost_info.advertiser_state = view.GetAdvertiserState();
on_found_on_lost_info.advertiser_address = view.GetAdvertiserAddress();
on_found_on_lost_info.advertiser_address_type = view.GetAdvertiserAddressType();
on_found_on_lost_info.advertiser_info_present = view.GetAdvtInfoPresent();
/* Extract the adv info details */
if (on_found_on_lost_info.advertiser_info_present == AdvtInfoPresent::ADVT_INFO_PRESENT) {
auto info_view = LEAdvertisementTrackingWithInfoEventView::Create(view);
ASSERT(info_view.IsValid());
on_found_on_lost_info.tx_power = info_view.GetTxPower();
on_found_on_lost_info.rssi = info_view.GetRssi();
on_found_on_lost_info.time_stamp = info_view.GetTimestamp();
auto adv_data = info_view.GetAdvPacket();
on_found_on_lost_info.adv_packet.reserve(adv_data.size());
on_found_on_lost_info.adv_packet.insert(on_found_on_lost_info.adv_packet.end(), adv_data.begin(), adv_data.end());
auto scan_rsp_data = info_view.GetScanResponse();
on_found_on_lost_info.scan_response.reserve(scan_rsp_data.size());
on_found_on_lost_info.scan_response.insert(
on_found_on_lost_info.scan_response.end(), scan_rsp_data.begin(), scan_rsp_data.end());
}
scanning_callbacks_->OnTrackAdvFoundLost(on_found_on_lost_info);
}
void OnPause() override {
paused_ = true;
scan_on_resume_ = is_scanning_;
stop_scan();
ack_pause();
}
void ack_pause() {
le_address_manager_->AckPause(this);
}
void OnResume() override {
paused_ = false;
if (scan_on_resume_ == true) {
start_scan();
}
le_address_manager_->AckResume(this);
}
ScanApiType api_type_;
Module* module_;
os::Handler* module_handler_;
hci::HciLayer* hci_layer_;
hci::Controller* controller_;
hci::VendorSpecificEventManager* vendor_specific_event_manager_;
hci::LeScanningInterface* le_scanning_interface_;
hci::LeAddressManager* le_address_manager_;
bool address_manager_registered_ = false;
NullScanningCallback null_scanning_callback_;
ScanningCallback* scanning_callbacks_ = &null_scanning_callback_;
std::vector<Scanner> scanners_;
bool is_scanning_ = false;
bool scan_on_resume_ = false;
bool paused_ = false;
AdvertisingCache advertising_cache_;
bool is_filter_support_ = false;
bool is_batch_scan_support_ = false;
LeScanType le_scan_type_ = LeScanType::ACTIVE;
uint32_t interval_ms_{1000};
uint16_t window_ms_{1000};
OwnAddressType own_address_type_{OwnAddressType::PUBLIC_DEVICE_ADDRESS};
LeScanningFilterPolicy filter_policy_{LeScanningFilterPolicy::ACCEPT_ALL};
BatchScanConfig batch_scan_config_;
std::map<ScannerId, std::vector<uint8_t>> batch_scan_result_cache_;
ScannerId tracker_id = kInvalidScannerId;
static void check_status(CommandCompleteView view) {
switch (view.GetCommandOpCode()) {
case (OpCode::LE_SET_SCAN_ENABLE): {
auto status_view = LeSetScanEnableCompleteView::Create(view);
ASSERT(status_view.IsValid());
ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS);
} break;
case (OpCode::LE_SET_EXTENDED_SCAN_ENABLE): {
auto status_view = LeSetExtendedScanEnableCompleteView::Create(view);
ASSERT(status_view.IsValid());
ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS);
} break;
case (OpCode::LE_SET_SCAN_PARAMETERS): {
auto status_view = LeSetScanParametersCompleteView::Create(view);
ASSERT(status_view.IsValid());
ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS);
} break;
case (OpCode::LE_EXTENDED_SCAN_PARAMS): {
auto status_view = LeExtendedScanParamsCompleteView::Create(view);
ASSERT(status_view.IsValid());
ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS);
} break;
case (OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS): {
auto status_view = LeSetExtendedScanParametersCompleteView::Create(view);
ASSERT(status_view.IsValid());
ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS);
} break;
default:
LOG_ALWAYS_FATAL("Unhandled event %s", OpCodeText(view.GetCommandOpCode()).c_str());
}
}
};
LeScanningManager::LeScanningManager() {
pimpl_ = std::make_unique<impl>(this);
}
void LeScanningManager::ListDependencies(ModuleList* list) {
list->add<hci::HciLayer>();
list->add<hci::VendorSpecificEventManager>();
list->add<hci::Controller>();
list->add<hci::AclManager>();
}
void LeScanningManager::Start() {
pimpl_->start(
GetHandler(),
GetDependency<hci::HciLayer>(),
GetDependency<hci::Controller>(),
GetDependency<AclManager>(),
GetDependency<VendorSpecificEventManager>());
}
void LeScanningManager::Stop() {
pimpl_->stop();
pimpl_.reset();
}
std::string LeScanningManager::ToString() const {
return "Le Scanning Manager";
}
void LeScanningManager::RegisterScanner(Uuid app_uuid) {
CallOn(pimpl_.get(), &impl::register_scanner, app_uuid);
}
void LeScanningManager::Unregister(ScannerId scanner_id) {
CallOn(pimpl_.get(), &impl::unregister_scanner, scanner_id);
}
void LeScanningManager::Scan(bool start) {
CallOn(pimpl_.get(), &impl::scan, start);
}
void LeScanningManager::SetScanParameters(LeScanType scan_type, uint16_t scan_interval, uint16_t scan_window) {
CallOn(pimpl_.get(), &impl::set_scan_parameters, scan_type, scan_interval, scan_window);
}
void LeScanningManager::ScanFilterEnable(bool enable) {
CallOn(pimpl_.get(), &impl::scan_filter_enable, enable);
}
void LeScanningManager::ScanFilterParameterSetup(
ApcfAction action, uint8_t filter_index, AdvertisingFilterParameter advertising_filter_parameter) {
CallOn(pimpl_.get(), &impl::scan_filter_parameter_setup, action, filter_index, advertising_filter_parameter);
}
void LeScanningManager::ScanFilterAdd(
uint8_t filter_index, std::vector<AdvertisingPacketContentFilterCommand> filters) {
CallOn(pimpl_.get(), &impl::scan_filter_add, filter_index, filters);
}
void LeScanningManager::BatchScanConifgStorage(
uint8_t batch_scan_full_max,
uint8_t batch_scan_truncated_max,
uint8_t batch_scan_notify_threshold,
ScannerId scanner_id) {
CallOn(
pimpl_.get(),
&impl::batch_scan_set_storage_parameter,
batch_scan_full_max,
batch_scan_truncated_max,
batch_scan_notify_threshold,
scanner_id);
}
void LeScanningManager::BatchScanEnable(
BatchScanMode scan_mode,
uint32_t duty_cycle_scan_window_slots,
uint32_t duty_cycle_scan_interval_slots,
BatchScanDiscardRule batch_scan_discard_rule) {
CallOn(
pimpl_.get(),
&impl::batch_scan_enable,
scan_mode,
duty_cycle_scan_window_slots,
duty_cycle_scan_interval_slots,
batch_scan_discard_rule);
}
void LeScanningManager::BatchScanDisable() {
CallOn(pimpl_.get(), &impl::batch_scan_disable);
}
void LeScanningManager::BatchScanReadReport(ScannerId scanner_id, BatchScanMode scan_mode) {
CallOn(pimpl_.get(), &impl::batch_scan_read_results, scanner_id, 0, scan_mode);
}
void LeScanningManager::TrackAdvertiser(ScannerId scanner_id) {
CallOn(pimpl_.get(), &impl::track_advertiser, scanner_id);
}
void LeScanningManager::RegisterScanningCallback(ScanningCallback* scanning_callback) {
CallOn(pimpl_.get(), &impl::register_scanning_callback, scanning_callback);
}
} // namespace hci
} // namespace bluetooth