xref: /aosp_15_r20/external/pigweed/pw_hex_dump/public/pw_hex_dump/log_bytes.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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