1 // Copyright 2022 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 #pragma once
15
16 #include <array>
17 #include <climits>
18 #include <cstdint>
19
20 #include "pw_assert/assert.h"
21 #include "pw_bluetooth/internal/hex.h"
22 #include "pw_span/span.h"
23 #include "pw_string/string.h"
24
25 namespace pw::bluetooth {
26
27 // A 128-bit Universally Unique Identifier (UUID).
28 // See Core Spec v5.3 Volume 3, Part B, Section 2.5.1.
29 //
30 // Bluetooth defines 16-bit, 32-bit and 128-bit UUID representations for a
31 // 128-bit UUID, all of which are used in the protocol. 16-bit UUIDs values
32 // define only the "YYYY" portion in the following UUID pattern (with XXXX set
33 // as 0), while 32-bit UUID value define the "XXXXYYYY" portion. When using
34 // these short UUIDs, the remaining bits are set by the Bluetooth_Base_UUID as
35 // follows:
36 // XXXXYYYY-0000-1000-8000-00805f9b34fb
37 //
38 // This class always stores UUID in their 128-bit representation in little
39 // endian format.
40 class Uuid {
41 public:
42 // String size of a hexadecimal representation of a UUID, not including the
43 // null terminator.
44 static constexpr size_t kHexStringSize = 36;
45
46 // Create a UUID from a span of 128-bit data. UUIDs are represented as
47 // little endian bytes.
Uuid(const span<const uint8_t,16> uuid_span)48 explicit constexpr Uuid(const span<const uint8_t, 16> uuid_span) : uuid_() {
49 for (size_t i = 0; i < sizeof(uuid_); i++) {
50 uuid_[i] = uuid_span[i];
51 }
52 }
53
54 // Create a UUID from its string representation. This is parsed manually here
55 // so it can be parsed at compile time with constexpr. A valid UUID is a hex
56 // string with hyphen separators at the 9th, 14th, 19th, and 24th
57 // positions, for example:
58 // "0000180a-0000-1000-8000-00805f9b34fb"
59 // The `str` parameter is byte longer than kHexStringSize so it can be
60 // initialized with literal strings including the null terminator, as in
61 // BluetoothBase().
Uuid(const char (& str)[kHexStringSize+1])62 constexpr Uuid(const char (&str)[kHexStringSize + 1]) : uuid_() {
63 size_t out_hex_index = 2 * sizeof(uuid_); // UUID is stored little-endian.
64 for (size_t i = 0; i < kHexStringSize; i++) {
65 // Indices at which we expect to find a hyphen ('-') in a UUID string.
66 if (i == 8 || i == 13 || i == 18 || i == 23) {
67 PW_ASSERT(str[i] == '-');
68 continue;
69 }
70 PW_ASSERT(str[i] != 0);
71 out_hex_index--;
72 uint16_t value = internal::HexToNibble(str[i]);
73 PW_ASSERT(value <= 0xf);
74 if (out_hex_index % 2 == 0) {
75 uuid_[out_hex_index / 2] |= value;
76 } else {
77 uuid_[out_hex_index / 2] = value << 4;
78 }
79 }
80 }
81
82 // The Bluetooth_Base_UUID defined by the specification. This is the base for
83 // all 16-bit and 32-bit short UUIDs.
84 static constexpr const Uuid& BluetoothBase();
85
Uuid()86 constexpr Uuid() : uuid_() {}
87
88 // Create a UUID combining 96-bits from a base UUID with a 16-bit or 32-bit
89 // value. 16-bit values will be extended to 32-bit ones, meaning the that the
90 // 16 most significant bits will be set to 0 regardless of the value on the
91 // base UUID.
Uuid(uint32_t short_uuid,const Uuid & base_uuid)92 constexpr Uuid(uint32_t short_uuid, const Uuid& base_uuid)
93 : uuid_(base_uuid.uuid_) {
94 uuid_[kBaseOffset] = short_uuid & 0xff;
95 uuid_[kBaseOffset + 1] = (short_uuid >> CHAR_BIT) & 0xff;
96 uuid_[kBaseOffset + 2] = (short_uuid >> CHAR_BIT * 2) & 0xff;
97 uuid_[kBaseOffset + 3] = (short_uuid >> CHAR_BIT * 3) & 0xff;
98 }
99
100 // Create a short UUID (32-bit or 16-bit) using the standard Bluetooth base
101 // UUID.
Uuid(uint32_t short_uuid)102 explicit constexpr Uuid(uint32_t short_uuid)
103 : Uuid(short_uuid, BluetoothBase()) {}
104
105 constexpr Uuid(const Uuid&) = default;
106 constexpr Uuid& operator=(const Uuid&) = default;
107
108 // Return a 2-byte span containing the 16-bit little endian representation of
109 // the UUID. This is useful when Same112BitBase(BluetoothBase()) is true.
As16BitSpan()110 constexpr span<const uint8_t, 2> As16BitSpan() const {
111 return span<const uint8_t, 2>{uuid_.data() + kBaseOffset, 2u};
112 }
113
114 // Return a 4-byte span containing the 32-bit little endian representation of
115 // the UUID. This is useful when Same96BitBase(BluetoothBase()) is true.
As32BitSpan()116 constexpr span<const uint8_t, 4> As32BitSpan() const {
117 return span<const uint8_t, 4>{uuid_.data() + kBaseOffset, 4u};
118 }
119
120 // Return the 128-bit (16-byte) little endian representation of the UUID.
As128BitSpan()121 constexpr span<const uint8_t, 16> As128BitSpan() const {
122 return span<const uint8_t, 16>{uuid_.data(), 16u};
123 }
124
125 // Return whether the UUID shares the same 112-bit base with another UUID.
126 // Sharing the same 112-bit base with BluetoothBase() means that this UUID
127 // can be resented as a 16-bit UUID.
Same112BitBase(const Uuid & other)128 constexpr bool Same112BitBase(const Uuid& other) const {
129 return Same96BitBase(other) && uuid_[14] == other.uuid_[14] &&
130 uuid_[15] == other.uuid_[15];
131 }
132
133 // Return whether the UUID shares the same 96-bit base with another UUID.
134 // Sharing the same 96-bit base with BluetoothBase() means that this UUID
135 // can be resented as a 32-bit UUID.
Same96BitBase(const Uuid & other)136 constexpr bool Same96BitBase(const Uuid& other) const {
137 for (size_t i = 0; i < 12; i++) {
138 if (uuid_[i] != other.uuid_[i])
139 return false;
140 }
141 return true;
142 }
143
144 // Return whether the UUID is a 16-bit UUID represented as 128-bit using the
145 // BluetoothBase() as the base.
Is16BitUuid()146 constexpr bool Is16BitUuid() const { return Same112BitBase(BluetoothBase()); }
147
148 // Return whether the UUID is a 32-bit UUID represented as 128-bit using the
149 // BluetoothBase() as the base.
Is32BitUuid()150 constexpr bool Is32BitUuid() const { return Same96BitBase(BluetoothBase()); }
151
152 // Return an inline pw_string representation of the UUID in hexadecimal.
ToString()153 constexpr InlineString<kHexStringSize> ToString() const {
154 InlineString<kHexStringSize> ret;
155 for (size_t i = uuid_.size(); i-- != 0;) {
156 ret += internal::NibbleToHex(uuid_[i] >> 4);
157 ret += internal::NibbleToHex(uuid_[i] & 0xf);
158 if ((i == 12) || (i == 10) || (i == 8) || (i == 6)) {
159 ret += '-';
160 }
161 }
162 return ret;
163 }
164
165 private:
166 // Offset at which the short 16-bit and 32-bit UUID little-endian data starts
167 // in the uuid_ array.
168 static constexpr size_t kBaseOffset = 12;
169
170 std::array<uint8_t, 16> uuid_;
171 };
172
173 namespace internal {
174 // When BluetoothBase() is used in constexpr expressions it would normally be
175 // evaluated to a final different Uuid, such as when used in Uuid(uint32_t),
176 // however if a reference to the return value of BluetoothBase() is needed this
177 // variable would be the only global symbol that provides it even if it is used
178 // from multiple translation units.
179 constexpr Uuid kBluetoothBaseUuid{"00000000-0000-1000-8000-00805F9B34FB"};
180 } // namespace internal
181
BluetoothBase()182 inline constexpr const Uuid& Uuid::BluetoothBase() {
183 return internal::kBluetoothBaseUuid;
184 }
185
186 // Uuid comparators:
187 constexpr bool operator==(const Uuid& a, const Uuid& b) {
188 const auto a_span = a.As128BitSpan();
189 const auto b_span = b.As128BitSpan();
190 for (size_t i = 0; i < a_span.size(); i++) {
191 if (a_span[i] != b_span[i]) {
192 return false;
193 }
194 }
195 return true;
196 }
197
198 constexpr bool operator!=(const Uuid& a, const Uuid& b) { return !(a == b); }
199
200 } // namespace pw::bluetooth
201