• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 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 <stdint.h>
17 
18 #include "pw_log_tokenized/config.h"
19 #include "pw_tokenizer/tokenize_to_global_handler_with_payload.h"
20 
21 // This macro implements PW_LOG using
22 // PW_TOKENIZE_TO_GLOBAL_HANDLER_WITH_PAYLOAD or an equivalent alternate macro
23 // provided by PW_LOG_TOKENIZED_ENCODE_MESSAGE. The log level, module token, and
24 // flags are packed into the payload argument.
25 //
26 // Two strings are tokenized in this macro:
27 //
28 //   - The log format string, tokenized in the default tokenizer domain.
29 //   - PW_LOG_MODULE_NAME, masked to 16 bits and tokenized in the
30 //     "pw_log_module_names" tokenizer domain.
31 //
32 // To use this macro, implement pw_tokenizer_HandleEncodedMessageWithPayload,
33 // which is defined in pw_tokenizer/tokenize.h. The log metadata can be accessed
34 // using pw::log_tokenized::Metadata. For example:
35 //
36 //   extern "C" void pw_tokenizer_HandleEncodedMessageWithPayload(
37 //       pw_tokenizer_Payload payload, const uint8_t data[], size_t size) {
38 //     pw::log_tokenized::Metadata metadata(payload);
39 //
40 //     if (metadata.level() >= kLogLevel && ModuleEnabled(metadata.module())) {
41 //       EmitLogMessage(data, size, metadata.flags());
42 //     }
43 //   }
44 //
45 #define PW_LOG_TOKENIZED_TO_GLOBAL_HANDLER_WITH_PAYLOAD(                     \
46     level, flags, message, ...)                                              \
47   do {                                                                       \
48     _PW_TOKENIZER_CONST uintptr_t _pw_log_module_token =                     \
49         PW_TOKENIZE_STRING_MASK("pw_log_module_names",                       \
50                                 ((1u << PW_LOG_TOKENIZED_MODULE_BITS) - 1u), \
51                                 PW_LOG_MODULE_NAME);                         \
52     PW_LOG_TOKENIZED_ENCODE_MESSAGE(                                         \
53         ((uintptr_t)(level) |                                                \
54          (_pw_log_module_token << PW_LOG_TOKENIZED_LEVEL_BITS) |             \
55          ((uintptr_t)(flags)                                                 \
56           << (PW_LOG_TOKENIZED_LEVEL_BITS + PW_LOG_TOKENIZED_MODULE_BITS))), \
57         PW_LOG_TOKENIZED_FORMAT_STRING(message),                             \
58         __VA_ARGS__);                                                        \
59   } while (0)
60 
61 #ifdef __cplusplus
62 
63 namespace pw {
64 namespace log_tokenized {
65 namespace internal {
66 
67 // This class, which is aliased to pw::log_tokenized::Metadata below, is used to
68 // access the log metadata packed into the tokenizer's payload argument.
69 template <unsigned kLevelBits,
70           unsigned kModuleBits,
71           unsigned kFlagBits,
72           typename T = uintptr_t>
73 class GenericMetadata {
74  public:
75   template <T log_level, T module, T flags>
Set()76   static constexpr GenericMetadata Set() {
77     static_assert(log_level < (1 << kLevelBits), "The level is too large!");
78     static_assert(module < (1 << kModuleBits), "The module is too large!");
79     static_assert(flags < (1 << kFlagBits), "The flags are too large!");
80 
81     return GenericMetadata(log_level | (module << kLevelBits) |
82                            (flags << (kModuleBits + kLevelBits)));
83   }
84 
GenericMetadata(T value)85   constexpr GenericMetadata(T value) : bits_(value) {}
86 
87   // The log level of this message.
level()88   constexpr T level() const { return bits_ & Mask<kLevelBits>(); }
89 
90   // The 16 bit tokenized version of the module name (PW_LOG_MODULE_NAME).
module()91   constexpr T module() const {
92     return (bits_ >> kLevelBits) & Mask<kModuleBits>();
93   }
94 
95   // The flags provided to the log call.
flags()96   constexpr T flags() const {
97     return (bits_ >> (kLevelBits + kModuleBits)) & Mask<kFlagBits>();
98   }
99 
100  private:
101   template <int bits>
Mask()102   static constexpr T Mask() {
103     return (T(1) << bits) - 1;
104   }
105 
106   T bits_;
107 
108   static_assert(kLevelBits + kModuleBits + kFlagBits <= sizeof(bits_) * 8);
109 };
110 
111 }  // namespace internal
112 
113 using Metadata = internal::GenericMetadata<PW_LOG_TOKENIZED_LEVEL_BITS,
114                                            PW_LOG_TOKENIZED_MODULE_BITS,
115                                            PW_LOG_TOKENIZED_FLAG_BITS>;
116 
117 }  // namespace log_tokenized
118 }  // namespace pw
119 
120 #endif  // __cpluplus
121