Skip to content

Commit 6c593d7

Browse files
deymoCQ Bot Account
authored and
CQ Bot Account
committed
pw_bluetooth: Make Address a class with constructors and helper methods
Similar to pw::bluetooth::Uuid, this patch makes pw::bluetooth::Address with helper constructors and methods to convert to and from its binary representation (6-byte array) and hexadecimal representation, such as "00:11:22:33:44:55". Test: Added unittests. Change-Id: I198a1c1f924f7b7901d56e064a5482c62810e2b4 Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/112933 Reviewed-by: Ben Lawson <benlawson@google.com> Reviewed-by: Marie Janssen <jamuraa@google.com> Reviewed-by: Wyatt Hepler <hepler@google.com> Commit-Queue: Alex Deymo <deymo@google.com>
1 parent cc55c96 commit 6c593d7

File tree

6 files changed

+184
-3
lines changed

6 files changed

+184
-3
lines changed

pw_bluetooth/BUILD.bazel

+11
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ licenses(["notice"])
2525
pw_cc_library(
2626
name = "pw_bluetooth",
2727
hdrs = [
28+
"public/pw_bluetooth/address.h",
2829
"public/pw_bluetooth/constants.h",
2930
"public/pw_bluetooth/gatt/client.h",
3031
"public/pw_bluetooth/gatt/constants.h",
@@ -56,6 +57,16 @@ pw_cc_library(
5657
],
5758
)
5859

60+
pw_cc_test(
61+
name = "address_test",
62+
srcs = [
63+
"address_test.cc",
64+
],
65+
deps = [
66+
":pw_bluetooth",
67+
],
68+
)
69+
5970
pw_cc_test(
6071
name = "api_test",
6172
srcs = [

pw_bluetooth/BUILD.gn

+7
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ pw_doc_group("docs") {
3131
pw_source_set("pw_bluetooth") {
3232
public_configs = [ ":public_include_path" ]
3333
public = [
34+
"public/pw_bluetooth/address.h",
3435
"public/pw_bluetooth/constants.h",
3536
"public/pw_bluetooth/gatt/client.h",
3637
"public/pw_bluetooth/gatt/constants.h",
@@ -65,12 +66,18 @@ pw_source_set("pw_bluetooth") {
6566
pw_test_group("tests") {
6667
enable_if = pw_chrono_SYSTEM_CLOCK_BACKEND != ""
6768
tests = [
69+
":address_test",
6870
":api_test",
6971
":result_test",
7072
":uuid_test",
7173
]
7274
}
7375

76+
pw_test("address_test") {
77+
sources = [ "address_test.cc" ]
78+
deps = [ ":pw_bluetooth" ]
79+
}
80+
7481
pw_test("api_test") {
7582
sources = [ "api_test.cc" ]
7683
deps = [ ":pw_bluetooth" ]

pw_bluetooth/CMakeLists.txt

+10
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ include($ENV{PW_ROOT}/pw_build/pigweed.cmake)
1616

1717
pw_add_module_library(pw_bluetooth
1818
HEADERS
19+
public/pw_bluetooth/address.h
1920
public/pw_bluetooth/gatt/client.h
2021
public/pw_bluetooth/gatt/constants.h
2122
public/pw_bluetooth/gatt/error.h
@@ -46,6 +47,15 @@ pw_add_module_library(pw_bluetooth
4647
pw_chrono.system_clock
4748
)
4849

50+
pw_add_test(pw_bluetooth.address_test
51+
SOURCES
52+
address_test.cc
53+
DEPS
54+
pw_bluetooth
55+
GROUPS
56+
pw_bluetooth
57+
)
58+
4959
pw_add_test(pw_bluetooth.api_test
5060
SOURCES
5161
api_test.cc

pw_bluetooth/address_test.cc

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
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+
#include "pw_bluetooth/address.h"
15+
16+
#include <array>
17+
#include <cstdint>
18+
19+
#include "gtest/gtest.h"
20+
#include "pw_span/span.h"
21+
22+
namespace pw::bluetooth {
23+
namespace {
24+
25+
constexpr Address kAddressString{"12:34:56:78:90:ab"};
26+
constexpr Address kAddressStringFromArray{pw::span<const uint8_t, 6>{
27+
std::array<const uint8_t, 6>{0xab, 0x90, 0x78, 0x56, 0x34, 0x12}}};
28+
29+
constexpr Address kAddressArray{pw::span<const uint8_t, 6>{
30+
std::array<const uint8_t, 6>{0x1a, 0x2b, 0x3c, 0x4d, 0x5e, 0x6f}}};
31+
32+
// Make sure these are actually constexpr.
33+
static_assert(kAddressString != kAddressArray, "constexpr check");
34+
static_assert(kAddressString == kAddressStringFromArray, "constexpr check");
35+
static_assert(kAddressArray.AsSpan().size() == 6, "constexpr check");
36+
37+
TEST(AddressTest, ConstructorTest) {
38+
static_assert(kAddressString.ToString() == "12:34:56:78:90:ab",
39+
"constexpr check");
40+
static_assert(kAddressArray.ToString() == "6f:5e:4d:3c:2b:1a",
41+
"constexpr check");
42+
static_assert(kAddressArray == Address("6f:5e:4d:3c:2b:1a"),
43+
"constexpr check");
44+
45+
static_assert(kAddressString == kAddressStringFromArray, "constexpr check");
46+
static_assert(kAddressString != kAddressArray, "constexpr check");
47+
48+
auto addr_span = kAddressString.AsSpan();
49+
EXPECT_EQ(addr_span.size(), 6u);
50+
EXPECT_EQ(addr_span.data()[0], 0xabu);
51+
EXPECT_EQ(addr_span.data()[1], 0x90u);
52+
}
53+
54+
} // namespace
55+
} // namespace pw::bluetooth
+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
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}.
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.
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.
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.
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

pw_bluetooth/public/pw_bluetooth/types.h

+1-3
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,14 @@
1717
#include <cstdint>
1818
#include <string_view>
1919

20+
#include "pw_bluetooth/address.h"
2021
#include "pw_bluetooth/uuid.h"
2122

2223
namespace pw::bluetooth {
2324

2425
// 64-bit unique value used by the system to identify peer devices.
2526
using PeerId = uint64_t;
2627

27-
// The device address bytes in little-endian order.
28-
using Address = std::array<uint8_t, 6>;
29-
3028
using DeviceName = std::string_view;
3129

3230
// A 128-bit secret key.

0 commit comments

Comments
 (0)