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