blob: 31ed2a592438800f944302ea0febfcd308cda9e5 [file] [log] [blame]
// Copyright 2022 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.
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/gap/android_vendor_capabilities.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/log.h"
namespace bt::gap {
namespace android_hci = pw::bluetooth::vendor::android_hci;
namespace {
bool AsBool(const android_hci::Capability& capability) {
return capability == android_hci::Capability::CAPABLE;
}
} // namespace
bool AndroidVendorCapabilities::SupportsVersion(uint8_t major,
uint8_t minor) const {
if (version_major_ > major) {
return true;
}
if (version_major_ == major && version_minor_ >= minor) {
return true;
}
return false;
}
AndroidVendorCapabilities AndroidVendorCapabilities::New(
const android_hci::LEGetVendorCapabilitiesCommandCompleteEventView& e) {
AndroidVendorCapabilities c;
if (e.status().Read() != pw::bluetooth::emboss::StatusCode::SUCCESS) {
bt_log(INFO,
"android_vendor_extensions",
"refusing to parse non-success vendor capabilities");
return c;
}
// Version 0.55
c.max_simultaneous_advertisement_ = e.max_advt_instances().Read();
c.supports_offloaded_rpa_ =
AsBool(e.offloaded_resolution_of_private_address().Read());
c.scan_results_storage_bytes_ = e.total_scan_results_storage().Read();
c.irk_list_size_ = e.max_irk_list_sz().Read();
c.supports_filtering_ = AsBool(e.filtering_support().Read());
c.max_filters_ = e.max_filter().Read();
c.supports_activity_energy_info_ =
AsBool(e.activity_energy_info_support().Read());
// There can be various versions of this command complete event sent by the
// Controller. As fields are added, the version_supported field is incremented
// to signify which fields are available. However, version_supported was only
// introduced into the command in Version 0.95. Controllers that use the base
// version, Version 0.55, don't have the version_supported field. As such, we
// must jump through some hoops to figure out which version we received,
// exactly.
//
// NOTE: Android's definition for this command complete event is available in
// AOSP: LeGetVendorCapabilitiesComplete and friends
// https://cs.android.com/android/platform/superproject/+/main:packages/modules/Bluetooth/system/gd/hci/hci_packets.pdl
//
// NOTE: An example implementation of how this command is filled in by a
// Controller is available within AOSP:
// le_get_vendor_capabilities_handler(...)
// https://cs.android.com/android/platform/superproject/main/+/main:packages/modules/Bluetooth/system/gd/hci/controller.cc
if (e.version_supported().major_number().IsComplete()) {
c.version_major_ = e.version_supported().major_number().Read();
}
if (e.version_supported().minor_number().IsComplete()) {
c.version_minor_ = e.version_supported().minor_number().Read();
}
// If we didn't receive a version number from the Controller, assume it's the
// base version, Version 0.55.
if (c.version_major_ == 0 && c.version_minor_ == 0) {
c.version_minor_ = 55;
}
// Version 0.95
if (c.SupportsVersion(0, 95)) {
c.max_advertisers_tracked_ = e.total_num_of_advt_tracked().Read();
c.supports_extended_scan_ = AsBool(e.extended_scan_support().Read());
c.supports_debug_logging_ = AsBool(e.debug_logging_supported().Read());
}
// Version 0.96
if (c.SupportsVersion(0, 96)) {
c.supports_offloading_le_address_generation_ =
AsBool(e.le_address_generation_offloading_support().Read());
}
// Version 0.98
if (c.SupportsVersion(0, 98)) {
c.a2dp_source_offload_capability_mask_ =
e.a2dp_source_offload_capability_mask().BackingStorage().ReadUInt();
c.supports_bluetooth_quality_report_ =
AsBool(e.bluetooth_quality_report_support().Read());
}
// Version 1.03
if (c.SupportsVersion(1, 03)) {
c.supports_dynamic_audio_buffer_ =
e.dynamic_audio_buffer_support().BackingStorage().ReadUInt();
}
// Version 1.04
if (c.SupportsVersion(1, 04)) {
c.a2dp_offload_v2_support_ = AsBool(e.a2dp_offload_v2_support().Read());
}
return c;
}
} // namespace bt::gap