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