1 // Copyright 2024 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
15 #pragma once
16
17 #include <array>
18 #include <cstddef>
19
20 #include "pw_bytes/span.h"
21 #include "pw_hex_dump/hex_dump.h"
22 #include "pw_log/log.h"
23 #include "pw_log/options.h"
24
25 namespace pw::dump {
26
27 /// Helper to log human-readable hex dumps to console.
28 ///
29 /// Example:
30 ///
31 /// @code{.cpp}
32 /// std::array<const std::byte, 9> my_data = {
33 /// std::byte('h'),
34 /// std::byte('e'),
35 /// std::byte('l'),
36 /// std::byte('l'),
37 /// std::byte('o'),
38 /// std::byte(0xde),
39 /// std::byte(0xad),
40 /// std::byte(0xbe),
41 /// std::byte(0xef),
42 /// };
43 ///
44 /// LogBytes(PW_LOG_LEVEL_DEBUG, my_data);
45 /// @endcode
46 ///
47 /// @code
48 /// DBG 0000: 68 65 6c 6c 6f de ad be ef hello....
49 /// @endcode
50 ///
51 /// To print other data types, obtain a `ConstByteSpan` view first:
52 ///
53 /// @code{.cpp}
54 /// LogBytes(PW_LOG_LEVEL_DEBUG, pw::as_bytes(pw::span("world!")));
55 /// @endcode
56 ///
57 /// @code
58 /// DBG 0000: 77 6f 72 6c 64 21 00 world!.
59 /// @endcode
60 ///
61 /// Use template arguments to modify the number of bytes printed per line:
62 ///
63 /// @code{.cpp}
64 /// LogBytes<8>(PW_LOG_LEVEL_DEBUG, pw::as_bytes(pw::span("hello world!")));
65 /// @endcode
66 ///
67 /// @code
68 /// DBG 0000: 68 65 6c 6c 6f 20 77 6f hello wo
69 /// DBG 0008: 72 6c 64 21 00 rld!.
70 /// @endcode
71 ///
72 ///
73 /// @tparam kBytesPerLine The number of input bytes to display per line.
74 /// Defaults to 16.
75 ///
76 /// @param[in] log_level The `PW_LOG_LEVEL` to log at.
77 ///
78 /// @param[in] bytes The data to log.
79 template <std::size_t kBytesPerLine = 16>
LogBytes(int log_level,pw::ConstByteSpan bytes)80 inline void LogBytes(int log_level, pw::ConstByteSpan bytes) {
81 // An input byte uses 3 bytes for the hex representation plus 1 for ASCII.
82 // 8 bytes go to offset, padding, and string termination.
83 const std::size_t kMaxLogLineLength = 8 + 4 * kBytesPerLine;
84
85 if (kBytesPerLine == 0) {
86 return;
87 }
88
89 std::array<char, kMaxLogLineLength> temp{};
90 const auto flags = pw::dump::FormattedHexDumper::Flags{
91 .bytes_per_line = kBytesPerLine,
92 .group_every = 1,
93 .show_ascii = true,
94 .show_header = false,
95 .prefix_mode = pw::dump::FormattedHexDumper::AddressMode::kOffset};
96 pw::dump::FormattedHexDumper hex_dumper(temp, flags);
97 if (hex_dumper.BeginDump(bytes).ok()) {
98 while (hex_dumper.DumpLine().ok()) {
99 PW_LOG(log_level,
100 PW_LOG_LEVEL,
101 PW_LOG_MODULE_NAME,
102 PW_LOG_FLAGS,
103 "%s",
104 temp.data());
105 }
106 }
107 }
108
109 } // namespace pw::dump
110