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