xref: /aosp_15_r20/external/pigweed/pw_bluetooth_sapphire/host/common/device_class.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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/common/device_class.h"
16 
17 #include <algorithm>
18 #include <climits>
19 
20 #include "pw_bluetooth_sapphire/internal/host/common/assert.h"
21 
22 namespace bt {
23 
24 namespace {
25 
bit_no_to_service_class(uint8_t bit_no)26 DeviceClass::ServiceClass bit_no_to_service_class(uint8_t bit_no) {
27   PW_DCHECK(bit_no >= 13);
28   PW_DCHECK(bit_no < 24);
29   switch (bit_no) {
30     case 13:
31       return DeviceClass::ServiceClass::kLimitedDiscoverableMode;
32     case 14:
33       return DeviceClass::ServiceClass::kLEAudio;
34     case 15:
35       return DeviceClass::ServiceClass::kReserved;
36     case 16:
37       return DeviceClass::ServiceClass::kPositioning;
38     case 17:
39       return DeviceClass::ServiceClass::kNetworking;
40     case 18:
41       return DeviceClass::ServiceClass::kRendering;
42     case 19:
43       return DeviceClass::ServiceClass::kCapturing;
44     case 20:
45       return DeviceClass::ServiceClass::kObjectTransfer;
46     case 21:
47       return DeviceClass::ServiceClass::kAudio;
48     case 22:
49       return DeviceClass::ServiceClass::kTelephony;
50     case 23:
51       return DeviceClass::ServiceClass::kInformation;
52   };
53   // Should be unreachable.
54   return DeviceClass::ServiceClass::kInformation;
55 }
56 
service_class_to_string(const DeviceClass::ServiceClass & serv)57 std::string service_class_to_string(const DeviceClass::ServiceClass& serv) {
58   switch (serv) {
59     case DeviceClass::ServiceClass::kLimitedDiscoverableMode:
60       return "Limited Discoverable Mode";
61     case DeviceClass::ServiceClass::kLEAudio:
62       return "LE Audio";
63     case DeviceClass::ServiceClass::kReserved:
64       return "Reserved";
65     case DeviceClass::ServiceClass::kPositioning:
66       return "Positioning";
67     case DeviceClass::ServiceClass::kNetworking:
68       return "Networking";
69     case DeviceClass::ServiceClass::kRendering:
70       return "Rendering";
71     case DeviceClass::ServiceClass::kCapturing:
72       return "Capturing";
73     case DeviceClass::ServiceClass::kObjectTransfer:
74       return "Object Transfer";
75     case DeviceClass::ServiceClass::kAudio:
76       return "Audio";
77     case DeviceClass::ServiceClass::kTelephony:
78       return "Telephony";
79     case DeviceClass::ServiceClass::kInformation:
80       return "Information";
81   }
82 }
83 
84 }  // namespace
85 
DeviceClass()86 DeviceClass::DeviceClass() : DeviceClass(MajorClass::kUnspecified) {}
87 
DeviceClass(MajorClass major_class)88 DeviceClass::DeviceClass(MajorClass major_class)
89     : bytes_{0x00, static_cast<uint8_t>(major_class), 0x00} {}
90 
DeviceClass(std::initializer_list<uint8_t> bytes)91 DeviceClass::DeviceClass(std::initializer_list<uint8_t> bytes) {
92   PW_DCHECK(bytes.size() == bytes_.size());
93   std::copy(bytes.begin(), bytes.end(), bytes_.begin());
94 }
95 
DeviceClass(uint32_t value)96 DeviceClass::DeviceClass(uint32_t value) {
97   PW_DCHECK(value < 1 << 24);  // field should only populate 24 bits
98   bytes_ = {
99       static_cast<uint8_t>((value >> 0) & 0xFF),
100       static_cast<uint8_t>((value >> 8) & 0xFF),
101       static_cast<uint8_t>((value >> 16) & 0xFF),
102   };
103 }
104 
to_int() const105 uint32_t DeviceClass::to_int() const {
106   uint32_t out = 0;
107   out |= bytes_[0];
108   out |= bytes_[1] << CHAR_BIT;
109   out |= bytes_[2] << 2 * CHAR_BIT;
110   return out;
111 }
112 
SetServiceClasses(const std::unordered_set<ServiceClass> & classes)113 void DeviceClass::SetServiceClasses(
114     const std::unordered_set<ServiceClass>& classes) {
115   for (const auto& c : classes) {
116     uint8_t bit = static_cast<uint8_t>(c);
117     if (bit >= 16) {
118       bytes_[2] |= 0x01 << (bit - 16);
119     } else if (bit >= 8) {
120       bytes_[1] |= 0x01 << (bit - 8);
121     }
122   }
123 }
124 
GetServiceClasses() const125 std::unordered_set<DeviceClass::ServiceClass> DeviceClass::GetServiceClasses()
126     const {
127   std::unordered_set<ServiceClass> classes;
128   for (uint8_t bit_no = 13; bit_no < 16; bit_no++) {
129     if (bytes_[1] & (0x01 << (bit_no - 8))) {
130       classes.emplace(bit_no_to_service_class(bit_no));
131     }
132   }
133   for (uint8_t bit_no = 16; bit_no < 24; bit_no++) {
134     if (bytes_[2] & (0x01 << (bit_no - 16))) {
135       classes.emplace(bit_no_to_service_class(bit_no));
136     }
137   }
138   return classes;
139 }
140 
ToString() const141 std::string DeviceClass::ToString() const {
142   std::string service_desc;
143   auto classes = GetServiceClasses();
144   if (!classes.empty()) {
145     auto it = classes.begin();
146     service_desc = " (" + service_class_to_string(*it);
147     ++it;
148     for (; it != classes.end(); ++it) {
149       service_desc += ", " + service_class_to_string(*it);
150     }
151     service_desc = service_desc + ")";
152   }
153   switch (major_class()) {
154     case MajorClass::kMiscellaneous:
155       return "Miscellaneous" + service_desc;
156     case MajorClass::kComputer:
157       return "Computer" + service_desc;
158     case MajorClass::kPhone:
159       return "Phone" + service_desc;
160     case MajorClass::kLAN:
161       return "LAN" + service_desc;
162     case MajorClass::kAudioVideo:
163       return "A/V" + service_desc;
164     case MajorClass::kPeripheral:
165       return "Peripheral" + service_desc;
166     case MajorClass::kImaging:
167       return "Imaging" + service_desc;
168     case MajorClass::kWearable:
169       return "Wearable" + service_desc;
170     case MajorClass::kToy:
171       return "Toy" + service_desc;
172     case MajorClass::kHealth:
173       return "Health Device" + service_desc;
174     case MajorClass::kUnspecified:
175       return "Unspecified" + service_desc;
176   };
177 
178   return "(unknown)";
179 }
180 
181 }  // namespace bt
182