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 #pragma once
16 #include <array>
17 #include <initializer_list>
18 #include <string>
19 #include <unordered_set>
20 
21 namespace bt {
22 
23 // Represents a 24-bit "Class of Device/Service" field.
24 // This data structure can be directly serialized into HCI command payloads.
25 // See the Bluetooth SIG Assigned Numbers for the Baseband
26 // (https://www.bluetooth.com/specifications/assigned-numbers/baseband)
27 // for the format.
28 class DeviceClass {
29  public:
30   using Bytes = std::array<uint8_t, 3>;
31 
32   enum class MajorClass : uint8_t {
33     kMiscellaneous = 0x00,
34     kComputer = 0x01,
35     kPhone = 0x02,
36     kLAN = 0x03,
37     kAudioVideo = 0x04,
38     kPeripheral = 0x05,
39     kImaging = 0x06,
40     kWearable = 0x07,
41     kToy = 0x08,
42     kHealth = 0x09,
43     kUnspecified = 0x1F,
44   };
45 
46   enum class ServiceClass : uint8_t {
47     kLimitedDiscoverableMode = 13,
48     kLEAudio = 14,
49     kReserved = 15,
50     kPositioning = 16,
51     kNetworking = 17,
52     kRendering = 18,
53     kCapturing = 19,
54     kObjectTransfer = 20,
55     kAudio = 21,
56     kTelephony = 22,
57     kInformation = 23,
58   };
59 
60   // Initializes the device to an uncategorized device with no services.
61   DeviceClass();
62 
63   // Initializes the contents from |bytes|, as they are represented from the
64   // controller (little-endian)
65   DeviceClass(std::initializer_list<uint8_t> bytes);
66 
67   // Initializes the contents from |uint32_t|
68   explicit DeviceClass(uint32_t value);
69 
70   // Initializes the contents using the given |major_class|.
71   explicit DeviceClass(MajorClass major_class);
72 
major_class()73   MajorClass major_class() const { return MajorClass(bytes_[1] & 0b1'1111); }
74 
75   uint8_t minor_class() const { return (bytes_[0] >> 2) & 0b11'1111; }
76 
bytes()77   const Bytes& bytes() const { return bytes_; }
78 
79   // Converts the DeviceClass into an integer with host-endianness. Only the
80   // lower 24 bits are used, and the highest 8 bits will be 0.
81   uint32_t to_int() const;
82 
83   // Sets the major service classes of this.
84   // Clears any service classes that are not set.
85   void SetServiceClasses(const std::unordered_set<ServiceClass>& classes);
86 
87   // Gets a set representing the major service classes that are set.
88   std::unordered_set<ServiceClass> GetServiceClasses() const;
89 
90   // Returns a string describing the device, like "Computer" or "Headphones"
91   std::string ToString() const;
92 
93   // Equality operators
94   bool operator==(const DeviceClass& rhs) const { return rhs.bytes_ == bytes_; }
95   bool operator!=(const DeviceClass& rhs) const { return rhs.bytes_ != bytes_; }
96 
97   // TODO(jamuraa): add MinorClass
98  private:
99   Bytes bytes_;
100 };
101 
102 static_assert(sizeof(DeviceClass) == 3,
103               "DeviceClass must take up exactly 3 bytes");
104 
105 }  // namespace bt
106