blob: 110d5425f52ea052f04f8a40b1315a9a3a13f2af [file] [log] [blame]
// Copyright 2021 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 <stdint.h>
#include "pw_log_tokenized/config.h"
#include "pw_tokenizer/tokenize_to_global_handler_with_payload.h"
// TODO(hepler): Remove this include.
#ifdef __cplusplus
#include "pw_log_tokenized/metadata.h"
#endif // __cplusplus
// This macro implements PW_LOG using
// PW_TOKENIZE_TO_GLOBAL_HANDLER_WITH_PAYLOAD or an equivalent alternate macro
// provided by PW_LOG_TOKENIZED_ENCODE_MESSAGE. The log level, module token, and
// flags are packed into the payload argument.
//
// Two strings are tokenized in this macro:
//
// - The log format string, tokenized in the default tokenizer domain.
// - PW_LOG_MODULE_NAME, masked to 16 bits and tokenized in the
// "pw_log_module_names" tokenizer domain.
//
// 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_tokenized_module_token = \
PW_TOKENIZE_STRING_MASK("pw_log_module_names", \
((1u << PW_LOG_TOKENIZED_MODULE_BITS) - 1u), \
PW_LOG_MODULE_NAME); \
const uintptr_t _pw_log_tokenized_level = level; \
PW_LOG_TOKENIZED_ENCODE_MESSAGE( \
(_PW_LOG_TOKENIZED_LEVEL(_pw_log_tokenized_level) | \
_PW_LOG_TOKENIZED_MODULE(_pw_log_tokenized_module_token) | \
_PW_LOG_TOKENIZED_FLAGS(flags) | _PW_LOG_TOKENIZED_LINE(__LINE__)), \
PW_LOG_TOKENIZED_FORMAT_STRING(message), \
__VA_ARGS__); \
} while (0)
// If the level field is present, clamp it to the maximum value.
#if PW_LOG_TOKENIZED_LEVEL_BITS == 0
#define _PW_LOG_TOKENIZED_LEVEL(value) ((uintptr_t)0)
#else
#define _PW_LOG_TOKENIZED_LEVEL(value) \
(value < ((uintptr_t)1 << PW_LOG_TOKENIZED_LEVEL_BITS) \
? value \
: ((uintptr_t)1 << PW_LOG_TOKENIZED_LEVEL_BITS) - 1)
#endif // PW_LOG_TOKENIZED_LEVEL_BITS
// If the line number field is present, shift it to its position. Set it to zero
// if the line number is too large for PW_LOG_TOKENIZED_LINE_BITS.
#if PW_LOG_TOKENIZED_LINE_BITS == 0
#define _PW_LOG_TOKENIZED_LINE(line) ((uintptr_t)0)
#else
#define _PW_LOG_TOKENIZED_LINE(line) \
((uintptr_t)(line < (1 << PW_LOG_TOKENIZED_LINE_BITS) ? line : 0) \
<< PW_LOG_TOKENIZED_LEVEL_BITS)
#endif // PW_LOG_TOKENIZED_LINE_BITS
// If the flags field is present, mask it and shift it to its position.
#if PW_LOG_TOKENIZED_FLAG_BITS == 0
#define _PW_LOG_TOKENIZED_FLAGS(value) ((uintptr_t)0)
#else
#define _PW_LOG_TOKENIZED_FLAGS(value) \
(((uintptr_t)(value) & (((uintptr_t)1 << PW_LOG_TOKENIZED_FLAG_BITS) - 1)) \
<< (PW_LOG_TOKENIZED_LEVEL_BITS + PW_LOG_TOKENIZED_LINE_BITS))
#endif // PW_LOG_TOKENIZED_FLAG_BITS
// If the module field is present, shift it to its position.
#if PW_LOG_TOKENIZED_MODULE_BITS == 0
#define _PW_LOG_TOKENIZED_MODULE(value) ((uintptr_t)0)
#else
#define _PW_LOG_TOKENIZED_MODULE(value) \
((uintptr_t)(value) << ((PW_LOG_TOKENIZED_LEVEL_BITS + \
PW_LOG_TOKENIZED_LINE_BITS + \
PW_LOG_TOKENIZED_FLAG_BITS)))
#endif // PW_LOG_TOKENIZED_MODULE_BITS