1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 #include "pw_bluetooth_sapphire/internal/host/gap/android_vendor_capabilities.h"
16
17 #include "pw_bluetooth_sapphire/internal/host/common/log.h"
18
19 namespace bt::gap {
20
21 namespace android_emb = pw::bluetooth::vendor::android_hci;
22
23 namespace {
AsBool(const android_emb::Capability & capability)24 bool AsBool(const android_emb::Capability& capability) {
25 return capability == android_emb::Capability::CAPABLE;
26 }
27 } // namespace
28
SupportsVersion(uint8_t major,uint8_t minor) const29 bool AndroidVendorCapabilities::SupportsVersion(uint8_t major,
30 uint8_t minor) const {
31 if (version_major_ > major) {
32 return true;
33 }
34
35 if (version_major_ == major && version_minor_ >= minor) {
36 return true;
37 }
38
39 return false;
40 }
41
New(const android_emb::LEGetVendorCapabilitiesCommandCompleteEventView & e)42 AndroidVendorCapabilities AndroidVendorCapabilities::New(
43 const android_emb::LEGetVendorCapabilitiesCommandCompleteEventView& e) {
44 AndroidVendorCapabilities c;
45
46 if (e.status().Read() != pw::bluetooth::emboss::StatusCode::SUCCESS) {
47 bt_log(INFO,
48 "android_vendor_extensions",
49 "refusing to parse non-success vendor capabilities");
50 return c;
51 }
52
53 // Version 0.55
54 c.max_simultaneous_advertisement_ = e.max_advt_instances().Read();
55 c.supports_offloaded_rpa_ =
56 AsBool(e.offloaded_resolution_of_private_address().Read());
57 c.scan_results_storage_bytes_ = e.total_scan_results_storage().Read();
58 c.irk_list_size_ = e.max_irk_list_sz().Read();
59 c.supports_filtering_ = AsBool(e.filtering_support().Read());
60 c.max_filters_ = e.max_filter().Read();
61 c.supports_activity_energy_info_ =
62 AsBool(e.activity_energy_info_support().Read());
63
64 // There can be various versions of this command complete event sent by the
65 // Controller. As fields are added, the version_supported field is incremented
66 // to signify which fields are available. However, version_supported was only
67 // introduced into the command in Version 0.95. Controllers that use the base
68 // version, Version 0.55, don't have the version_supported field. As such, we
69 // must jump through some hoops to figure out which version we received,
70 // exactly.
71 //
72 // NOTE: Android's definition for this command complete event is available in
73 // AOSP: LeGetVendorCapabilitiesComplete and friends
74 // https://cs.android.com/android/platform/superproject/+/main:packages/modules/Bluetooth/system/gd/hci/hci_packets.pdl
75 //
76 // NOTE: An example implementation of how this command is filled in by a
77 // Controller is available within AOSP:
78 // le_get_vendor_capabilities_handler(...)
79 // https://cs.android.com/android/platform/superproject/main/+/main:packages/modules/Bluetooth/system/gd/hci/controller.cc
80 if (e.version_supported().major_number().IsComplete()) {
81 c.version_major_ = e.version_supported().major_number().Read();
82 }
83
84 if (e.version_supported().minor_number().IsComplete()) {
85 c.version_minor_ = e.version_supported().minor_number().Read();
86 }
87
88 // If we didn't receive a version number from the Controller, assume it's the
89 // base version, Version 0.55.
90 if (c.version_major_ == 0 && c.version_minor_ == 0) {
91 c.version_minor_ = 55;
92 }
93
94 // Version 0.95
95 if (c.SupportsVersion(0, 95)) {
96 c.max_advertisers_tracked_ = e.total_num_of_advt_tracked().Read();
97 c.supports_extended_scan_ = AsBool(e.extended_scan_support().Read());
98 c.supports_debug_logging_ = AsBool(e.debug_logging_supported().Read());
99 }
100
101 // Version 0.96
102 if (c.SupportsVersion(0, 96)) {
103 c.supports_offloading_le_address_generation_ =
104 AsBool(e.le_address_generation_offloading_support().Read());
105 }
106
107 // Version 0.98
108 if (c.SupportsVersion(0, 98)) {
109 c.a2dp_source_offload_capability_mask_ =
110 e.a2dp_source_offload_capability_mask().BackingStorage().ReadUInt();
111 c.supports_bluetooth_quality_report_ =
112 AsBool(e.bluetooth_quality_report_support().Read());
113 }
114
115 // Version 1.03
116 if (c.SupportsVersion(1, 03)) {
117 c.supports_dynamic_audio_buffer_ =
118 e.dynamic_audio_buffer_support().BackingStorage().ReadUInt();
119 }
120
121 // Version 1.04
122 if (c.SupportsVersion(1, 04)) {
123 c.a2dp_offload_v2_support_ = AsBool(e.a2dp_offload_v2_support().Read());
124 }
125
126 return c;
127 }
128
129 } // namespace bt::gap
130