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 <cstdint> 18 19 #include "pw_assert/assert.h" 20 #include "pw_bluetooth/internal/hex.h" 21 #include "pw_span/span.h" 22 #include "pw_string/string.h" 23 24 namespace pw::bluetooth { 25 26 // A 48-bit bluetooth device address (BD_ADDR) in little endian format. 27 // See Core Spec v5.3 Volume 2, Part B, Section 1.2. 28 class Address { 29 public: 30 enum class Type : uint8_t { 31 kPublic, 32 kRandomStatic, 33 kRandomResolvablePrivate, 34 kRandomNonResolvablePrivate, 35 }; 36 // String size of a hexadecimal representation of an Address, not including 37 // the null terminator. 38 static constexpr size_t kHexStringSize = 17; 39 40 // Create an Address from its binary representation. 41 // The first byte in the span is the last one in the hex representation, thus 42 // the BD_ADDR 00:11:22:33:44:55 should be created from the span with bytes: 43 // {0x55, 0x44, 0x33, 0x22, 0x11, 0x00}. Address(const span<const uint8_t,6> addr_span)44 constexpr Address(const span<const uint8_t, 6> addr_span) : addr_() { 45 static_assert(addr_span.size() == sizeof(addr_)); 46 for (size_t i = 0; i < sizeof(addr_); i++) { 47 addr_[i] = addr_span[i]; 48 } 49 } 50 51 // Create an address from the hex format "00:11:22:33:44:55". The passed 52 // string must have a length of 17 and a ":" character on the 3rd, 6th, 9th, 53 // 12th and 15th positions. The hexadecimal representation is such that the 54 // first byte in the string is the last byte in the binary representation. Address(const char (& str_addr)[kHexStringSize+1])55 constexpr Address(const char (&str_addr)[kHexStringSize + 1]) : addr_() { 56 PW_ASSERT((str_addr[2] == ':') && (str_addr[5] == ':') && 57 (str_addr[8] == ':') && (str_addr[11] == ':') && 58 (str_addr[14] == ':')); 59 for (size_t i = 0; i < sizeof(addr_); i++) { 60 uint16_t value = (internal::HexToNibble(str_addr[3 * i]) << 4u) | 61 internal::HexToNibble(str_addr[3 * i + 1]); 62 addr_[sizeof(addr_) - 1 - i] = value; 63 PW_ASSERT(value <= 0xff); 64 } 65 } 66 67 // Return the bluetooth address a the 6-byte binary representation. AsSpan()68 constexpr span<const uint8_t, 6> AsSpan() const { 69 return span<const uint8_t, 6>{addr_.data(), addr_.size()}; 70 } 71 72 // Return an inline pw_string representation of the Address in hexadecimal 73 // using ":" characters as byte separator. ToString()74 constexpr InlineString<kHexStringSize> ToString() const { 75 InlineString<kHexStringSize> ret; 76 for (size_t i = addr_.size(); i-- != 0;) { 77 ret += internal::NibbleToHex(addr_[i] >> 4); 78 ret += internal::NibbleToHex(addr_[i] & 0xf); 79 if (i) { 80 ret += ':'; 81 } 82 } 83 return ret; 84 } 85 86 private: 87 std::array<uint8_t, 6> addr_; 88 }; 89 90 // Address comparators: 91 constexpr bool operator==(const Address& a, const Address& b) { 92 const auto a_span = a.AsSpan(); 93 const auto b_span = b.AsSpan(); 94 for (size_t i = 0; i < a_span.size(); i++) { 95 if (a_span[i] != b_span[i]) { 96 return false; 97 } 98 } 99 return true; 100 } 101 102 constexpr bool operator!=(const Address& a, const Address& b) { 103 return !(a == b); 104 } 105 106 } // namespace pw::bluetooth 107