blob: 1589e88deb60cb32e2e759a930d8b01e088a6187 [file] [log] [blame]
// Copyright 2020 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
#pragma once
#include <assert.h>
#include <stdint.h>
#include "pw_log/options.h"
#include "pw_preprocessor/concat.h"
#include "pw_tokenizer/tokenize_to_global_handler_with_payload.h"
// This macro implements PW_LOG, using
// PW_TOKENIZE_TO_GLOBAL_HANDLER_WITH_PAYLOAD. The log level, module token, and
// flags are packed into the payload argument.
//
// To use this macro, implement pw_tokenizer_HandleEncodedMessageWithPayload,
// which is defined in pw_tokenizer/tokenize.h. The log metadata can be accessed
// using pw::log_tokenized::Metadata. For example:
//
// extern "C" void pw_tokenizer_HandleEncodedMessageWithPayload(
// pw_tokenizer_Payload payload, const uint8_t data[], size_t size) {
// pw::log_tokenized::Metadata metadata(payload);
//
// if (metadata.level() >= kLogLevel && ModuleEnabled(metadata.module())) {
// EmitLogMessage(data, size, metadata.flags());
// }
// }
//
#define PW_LOG_TOKENIZED_TO_GLOBAL_HANDLER_WITH_PAYLOAD( \
level, flags, message, ...) \
do { \
_PW_TOKENIZER_CONST uintptr_t _pw_log_module_token = \
PW_TOKENIZE_STRING_DOMAIN("log_module_names", PW_LOG_MODULE_NAME); \
PW_TOKENIZE_TO_GLOBAL_HANDLER_WITH_PAYLOAD( \
((uintptr_t)(level) | \
((_pw_log_module_token & \
((1u << _PW_LOG_TOKENIZED_MODULE_BITS) - 1u)) \
<< _PW_LOG_TOKENIZED_LEVEL_BITS) | \
((uintptr_t)(flags) \
<< (_PW_LOG_TOKENIZED_LEVEL_BITS + _PW_LOG_TOKENIZED_MODULE_BITS))), \
PW_LOG_TOKENIZED_FORMAT_STRING(message), \
__VA_ARGS__); \
} while (0)
// By default, log format strings include the PW_LOG_MODULE_NAME, if defined.
#ifndef PW_LOG_TOKENIZED_FORMAT_STRING
#define PW_LOG_TOKENIZED_FORMAT_STRING(string) \
PW_CONCAT(_PW_LOG_TOKENIZED_FMT_, PW_LOG_MODULE_NAME_DEFINED)(string)
#define _PW_LOG_TOKENIZED_FMT_0(string) string
#define _PW_LOG_TOKENIZED_FMT_1(string) PW_LOG_MODULE_NAME " " string
#endif // PW_LOG_TOKENIZED_FORMAT_STRING
// The log level, module token, and flag bits are packed into the tokenizer's
// payload argument, which is typically 32 bits. These macros specify the number
// of bits to use for each field.
#define _PW_LOG_TOKENIZED_LEVEL_BITS 6
#define _PW_LOG_TOKENIZED_MODULE_BITS 16
#define _PW_LOG_TOKENIZED_FLAG_BITS 10
#ifdef __cplusplus
static_assert((_PW_LOG_TOKENIZED_LEVEL_BITS + _PW_LOG_TOKENIZED_MODULE_BITS +
_PW_LOG_TOKENIZED_FLAG_BITS) == 32,
"Log metadata must fit in a 32-bit integer");
namespace pw {
namespace log_tokenized {
namespace internal {
// This class, which is aliased to pw::log_tokenized::Metadata below, is used to
// access the log metadata packed into the tokenizer's payload argument.
template <unsigned level_bits,
unsigned module_bits,
unsigned flag_bits,
typename T = uintptr_t>
class GenericMetadata {
public:
template <T log_level, T module, T flags>
static constexpr GenericMetadata Set() {
static_assert(log_level < (1 << level_bits), "The level is too large!");
static_assert(module < (1 << module_bits), "The module is too large!");
static_assert(flags < (1 << flag_bits), "The flags are too large!");
return GenericMetadata(log_level | (module << level_bits) |
(flags << (module_bits + level_bits)));
}
constexpr GenericMetadata(T value) : bits_(value) {}
// The log level of this message.
constexpr T level() const { return bits_ & Mask<level_bits>(); }
// The 16 bit tokenized version of the module name (PW_LOG_MODULE_NAME).
constexpr T module() const {
return (bits_ >> level_bits) & Mask<module_bits>();
}
// The flags provided to the log call.
constexpr T flags() const {
return (bits_ >> (level_bits + module_bits)) & Mask<flag_bits>();
}
private:
template <int bits>
static constexpr T Mask() {
return (T(1) << bits) - 1;
}
T bits_;
static_assert(level_bits + module_bits + flag_bits <= sizeof(bits_) * 8);
};
} // namespace internal
using Metadata = internal::GenericMetadata<_PW_LOG_TOKENIZED_LEVEL_BITS,
_PW_LOG_TOKENIZED_MODULE_BITS,
_PW_LOG_TOKENIZED_FLAG_BITS>;
} // namespace log_tokenized
} // namespace pw
#endif // __cpluplus