Direct-BT  2.3.1
Direct-BT - Direct Bluetooth Programming.
UUID.cpp
Go to the documentation of this file.
1 /*
2  * Author: Sven Gothel <sgothel@jausoft.com>
3  * Copyright (c) 2020 Gothel Software e.K.
4  * Copyright (c) 2020 ZAFENA AB
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be
15  * included in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  */
25 
26 #include <jau/debug.hpp>
27 
28 #include "UUID.hpp"
29 
30 
31 using namespace direct_bt;
32 
33 // BASE_UUID '00000000-0000-1000-8000-00805F9B34FB'
34 static uint8_t bt_base_uuid_be[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
35  0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB };
37 
39  switch( static_cast<TypeSize>(size) ) {
43  }
44  throw jau::IllegalArgumentException("Given size "+std::to_string(size)+", not matching uuid16_t, uuid32_t or uuid128_t", E_FILE_LINE);
45 }
46 
47 std::unique_ptr<const uuid_t> uuid_t::create(TypeSize t, uint8_t const * const buffer, jau::nsize_t const byte_offset, bool littleEndian) {
48  if( TypeSize::UUID16_SZ == t ) {
49  return std::unique_ptr<const uuid_t>(new uuid16_t(buffer, byte_offset, littleEndian));
50  } else if( TypeSize::UUID32_SZ == t ) {
51  return std::unique_ptr<const uuid_t>(new uuid32_t(buffer, byte_offset, littleEndian));
52  } else if( TypeSize::UUID128_SZ == t ) {
53  return std::unique_ptr<const uuid_t>(new uuid128_t(buffer, byte_offset, littleEndian));
54  }
55  throw jau::IllegalArgumentException("Unknown Type "+std::to_string(static_cast<jau::nsize_t>(t)), E_FILE_LINE);
56 }
57 
58 uuid128_t uuid_t::toUUID128(uuid128_t const & base_uuid, jau::nsize_t const uuid32_le_octet_index) const noexcept {
59  switch(type) {
60  case TypeSize::UUID16_SZ: return uuid128_t(*((uuid16_t*)this), base_uuid, uuid32_le_octet_index);
61  case TypeSize::UUID32_SZ: return uuid128_t(*((uuid32_t*)this), base_uuid, uuid32_le_octet_index);
62  case TypeSize::UUID128_SZ: return uuid128_t(*((uuid128_t*)this));
63  }
64  ABORT("Unknown Type %d", static_cast<jau::nsize_t>(type));
65  abort(); // never reached
66 }
67 
68 std::string uuid_t::toUUID128String(uuid128_t const & base_uuid, jau::nsize_t const le_octet_index) const noexcept {
69  (void)base_uuid;
70  (void)le_octet_index;
71  return "";
72 }
73 
74 uuid128_t::uuid128_t(uuid16_t const & uuid16, uuid128_t const & base_uuid, jau::nsize_t const uuid16_le_octet_index) noexcept
75 : uuid_t(TypeSize::UUID128_SZ), value(merge_uint128(uuid16.value, base_uuid.value, uuid16_le_octet_index)) {}
76 
77 uuid128_t::uuid128_t(uuid32_t const & uuid32, uuid128_t const & base_uuid, jau::nsize_t const uuid32_le_octet_index) noexcept
78 : uuid_t(TypeSize::UUID128_SZ), value(merge_uint128(uuid32.value, base_uuid.value, uuid32_le_octet_index)) {}
79 
80 std::string uuid16_t::toString() const noexcept {
81  const jau::nsize_t length = 4;
82  std::string str;
83  str.reserve(length+1); // including EOS for snprintf
84  str.resize(length);
85 
86  const jau::nsize_t count = snprintf(&str[0], str.capacity(), "%.4x", value);
87  if( length != count ) {
88  ABORT("UUID16 string not of length %d but %d", length, count);
89  }
90  return str;
91 }
92 
93 std::string uuid16_t::toUUID128String(uuid128_t const & base_uuid, jau::nsize_t const le_octet_index) const noexcept
94 {
95  uuid128_t u128(*this, base_uuid, le_octet_index);
96  return u128.toString();
97 }
98 
99 std::string uuid32_t::toString() const noexcept {
100  const jau::nsize_t length = 8;
101  std::string str;
102  str.reserve(length+1); // including EOS for snprintf
103  str.resize(length);
104 
105  const jau::nsize_t count = snprintf(&str[0], str.capacity(), "%.8x", value);
106  if( length != count ) {
107  ABORT("UUID32 string not of length %d but %d", length, count);
108  }
109  return str;
110 }
111 
112 std::string uuid32_t::toUUID128String(uuid128_t const & base_uuid, jau::nsize_t const le_octet_index) const noexcept
113 {
114  uuid128_t u128(*this, base_uuid, le_octet_index);
115  return u128.toString();
116 }
117 
118 std::string uuid128_t::toString() const noexcept {
119  // 87654321-0000-1000-8000-00805F9B34FB
120  // 0 1 2 3 4 5
121  // LE: low-mem - FB349B5F0800-0080-0010-0000-12345678 - high-mem
122  // 5 4 3 2 1 0
123  //
124  // BE: low-mem - 87654321-0000-1000-8000-00805F9B34FB - high-mem
125  // 0 1 2 3 4 5
126  //
127  const jau::nsize_t length = 36;
128  std::string str;
129  str.reserve(length+1); // including EOS for snprintf
130  str.resize(length);
131  uint32_t part0, part4;
132  uint16_t part1, part2, part3, part5;
133 
134  // snprintf uses host data type, in which values are stored,
135  // hence no endian conversion
136 #if __BYTE_ORDER == __BIG_ENDIAN
137  part0 = jau::get_uint32(value.data, 0);
138  part1 = jau::get_uint16(value.data, 4);
139  part2 = jau::get_uint16(value.data, 6);
140  part3 = jau::get_uint16(value.data, 8);
141  part4 = jau::get_uint32(value.data, 10);
142  part5 = jau::get_uint16(value.data, 14);
143 #elif __BYTE_ORDER == __LITTLE_ENDIAN
144  part5 = jau::get_uint16(value.data, 0);
145  part4 = jau::get_uint32(value.data, 2);
146  part3 = jau::get_uint16(value.data, 6);
147  part2 = jau::get_uint16(value.data, 8);
148  part1 = jau::get_uint16(value.data, 10);
149  part0 = jau::get_uint32(value.data, 12);
150 #else
151 #error "Unexpected __BYTE_ORDER"
152 #endif
153  const jau::nsize_t count = snprintf(&str[0], str.capacity(), "%.8x-%.4x-%.4x-%.4x-%.8x%.4x",
154  part0, part1, part2, part3, part4, part5);
155  if( length != count ) {
156  ABORT("UUID128 string not of length %d but %d", length, count);
157  }
158  return str;
159 }
160 
161 uuid128_t::uuid128_t(const std::string str)
162 : uuid_t(TypeSize::UUID128_SZ)
163 {
164  uint32_t part0, part4;
165  uint16_t part1, part2, part3, part5;
166 
167  if( 36 != str.length() ) {
168  std::string msg("UUID128 string not of length 36 but ");
169  msg.append(std::to_string(str.length()));
170  msg.append(": "+str);
172  }
173  if ( sscanf(str.c_str(), "%08x-%04hx-%04hx-%04hx-%08x%04hx",
174  &part0, &part1, &part2, &part3, &part4, &part5) != 6 )
175  {
176  std::string msg("UUID128 string not in format '00000000-0000-1000-8000-00805F9B34FB' but "+str);
178  }
179 
180  // sscanf provided host data type, in which we store the values,
181  // hence no endian conversion
182 #if __BYTE_ORDER == __BIG_ENDIAN
183  jau::put_uint32(value.data, 0, part0);
184  jau::put_uint16(value.data, 4, part1);
185  jau::put_uint16(value.data, 6, part2);
186  jau::put_uint16(value.data, 8, part3);
187  jau::put_uint32(value.data, 10, part4);
188  jau::put_uint16(value.data, 14, part5);
189 #elif __BYTE_ORDER == __LITTLE_ENDIAN
190  jau::put_uint16(value.data, 0, part5);
191  jau::put_uint32(value.data, 2, part4);
192  jau::put_uint16(value.data, 6, part3);
193  jau::put_uint16(value.data, 8, part2);
194  jau::put_uint16(value.data, 10, part1);
195  jau::put_uint32(value.data, 12, part0);
196 #else
197 #error "Unexpected __BYTE_ORDER"
198 #endif
199 }
200 
direct_bt::uuid_t::toUUID128
uuid128_t toUUID128(uuid128_t const &base_uuid=BT_BASE_UUID, jau::nsize_t const uuid32_le_octet_index=12) const noexcept
Definition: UUID.cpp:58
direct_bt::uuid_t::create
static std::unique_ptr< const uuid_t > create(TypeSize const t, uint8_t const *const buffer, jau::nsize_t const byte_offset, bool const littleEndian)
Definition: UUID.cpp:47
direct_bt::uuid_t::TypeSize::UUID128_SZ
@ UUID128_SZ
direct_bt::uuid128_t::toString
std::string toString() const noexcept override
Definition: UUID.cpp:118
jau::IllegalArgumentException
Definition: basic_types.hpp:111
direct_bt
Definition: ATTPDUTypes.hpp:171
direct_bt::uuid128_t
Definition: UUID.hpp:152
jau::merge_uint128
uint128_t merge_uint128(uint16_t const uuid16, uint128_t const &base_uuid, nsize_t const uuid16_le_octet_index)
Merge the given 'uuid16' into a 'base_uuid' copy at the given little endian 'uuid16_le_octet_index' p...
Definition: basic_types.cpp:92
direct_bt::uuid16_t
Definition: UUID.hpp:98
jau::put_uint32
constexpr void put_uint32(uint8_t *buffer, nsize_t const byte_offset, const uint32_t v) noexcept
Definition: byte_util.hpp:615
direct_bt::uuid16_t::value
uint16_t value
Definition: UUID.hpp:100
jau::to_string
PRAGMA_DISABLE_WARNING_POP constexpr_cxx20 std::string to_string(const endian &v) noexcept
Return std::string representation of the given jau::endian.
Definition: byte_util.hpp:198
bt_base_uuid_be
static uint8_t bt_base_uuid_be[]
Definition: UUID.cpp:34
direct_bt::BT_BASE_UUID
uuid128_t BT_BASE_UUID
Bluetooth UUID https://www.bluetooth.com/specifications/assigned-numbers/service-discovery/
E_FILE_LINE
#define E_FILE_LINE
Definition: basic_types.hpp:64
ABORT
#define ABORT(...)
Use for unconditional ::abort() call with given messages, prefix '[elapsed_time] ABORT @ FILE:LINE: '...
Definition: debug.hpp:124
direct_bt::uuid16_t::toUUID128String
std::string toUUID128String(uuid128_t const &base_uuid=BT_BASE_UUID, jau::nsize_t const le_octet_index=12) const noexcept override
Definition: UUID.cpp:93
direct_bt::uuid_t::TypeSize
TypeSize
Underlying integer value present octet count.
Definition: UUID.hpp:55
direct_bt::uuid32_t::value
uint32_t value
Definition: UUID.hpp:127
direct_bt::uuid_t::TypeSize::UUID32_SZ
@ UUID32_SZ
jau::uint128_t::data
uint8_t data[16]
Definition: int_types.hpp:83
direct_bt::uuid128_t::value
jau::uint128_t value
Definition: UUID.hpp:154
direct_bt::uuid32_t
Definition: UUID.hpp:125
jau::get_uint32
constexpr uint32_t get_uint32(uint8_t const *buffer, nsize_t const byte_offset) noexcept
Definition: byte_util.hpp:623
UUID.hpp
debug.hpp
direct_bt::uuid128_t::uuid128_t
uuid128_t() noexcept
Definition: UUID.hpp:156
direct_bt::uuid_t::toUUID128String
virtual std::string toUUID128String(uuid128_t const &base_uuid=BT_BASE_UUID, jau::nsize_t const le_octet_index=12) const noexcept
Definition: UUID.cpp:68
jau::nsize_t
uint_fast32_t nsize_t
Natural 'size_t' alternative using uint_fast32_t as its natural sized type.
Definition: int_types.hpp:44
jau::get_uint16
constexpr uint16_t get_uint16(uint8_t const *buffer, nsize_t const byte_offset) noexcept
Definition: byte_util.hpp:586
direct_bt::uuid32_t::toString
std::string toString() const noexcept override
Definition: UUID.cpp:99
jau::put_uint16
constexpr void put_uint16(uint8_t *buffer, nsize_t const byte_offset, const uint16_t v) noexcept
Definition: byte_util.hpp:561
direct_bt::uuid_t
Definition: UUID.hpp:52
direct_bt::uuid32_t::toUUID128String
std::string toUUID128String(uuid128_t const &base_uuid=BT_BASE_UUID, jau::nsize_t const le_octet_index=12) const noexcept override
Definition: UUID.cpp:112
direct_bt::uuid_t::TypeSize::UUID16_SZ
@ UUID16_SZ
direct_bt::uuid16_t::toString
std::string toString() const noexcept override
Definition: UUID.cpp:80
direct_bt::uuid_t::toTypeSize
static TypeSize toTypeSize(const jau::nsize_t size)
Definition: UUID.cpp:38