/*
 * Copyright (c) 2018 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: Apache-2.0
 */
#ifndef ZEPHYR_INCLUDE_LOGGING_LOG_CTRL_H_
#define ZEPHYR_INCLUDE_LOGGING_LOG_CTRL_H_

#include <zephyr/kernel.h>
#include <zephyr/logging/log_backend.h>
#include <zephyr/logging/log_msg.h>
#include <zephyr/logging/log_internal.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @brief Logger
 * @defgroup logger Logger system
 * @since 1.13
 * @ingroup logging
 * @{
 * @}
 */

/**
 * @brief Logger control API
 * @defgroup log_ctrl Logger control API
 * @since 1.13
 * @ingroup logger
 * @{
 */

typedef log_timestamp_t (*log_timestamp_get_t)(void);

/** @brief Function system initialization of the logger.
 *
 * Function is called during start up to allow logging before user can
 * explicitly initialize the logger.
 */
void log_core_init(void);

/**
 * @brief Function for user initialization of the logger.
 *
 */
void log_init(void);

/** @brief Trigger the log processing thread to process logs immediately.
 *
 *  @note Function  has no effect when CONFIG_LOG_MODE_IMMEDIATE is set.
 */
void log_thread_trigger(void);

/**
 * @brief Function for providing thread which is processing logs.
 *
 * See CONFIG_LOG_PROCESS_TRIGGER_THRESHOLD.
 *
 * @note Function has asserts and has no effect when CONFIG_LOG_PROCESS_THREAD is set.
 *
 * @param process_tid Process thread id. Used to wake up the thread.
 */
void log_thread_set(k_tid_t process_tid);

/**
 * @brief Function for providing timestamp function.
 *
 * @param timestamp_getter	Timestamp function.
 * @param freq			Timestamping frequency.
 *
 * @return 0 on success or error.
 */
int log_set_timestamp_func(log_timestamp_get_t timestamp_getter,
			   uint32_t freq);

/**
 * @brief Switch the logger subsystem to the panic mode.
 *
 * Returns immediately if the logger is already in the panic mode.
 *
 * @details On panic the logger subsystem informs all backends about panic mode.
 *          Backends must switch to blocking mode or halt. All pending logs
 *          are flushed after switching to panic mode. In panic mode, all log
 *          messages must be processed in the context of the call.
 */
__syscall void log_panic(void);

/**
 * @brief Process one pending log message.
 *
 * @retval true There are more messages pending to be processed.
 * @retval false No messages pending.
 */
__syscall bool log_process(void);

/**
 * @brief Return number of buffered log messages.
 *
 * @return Number of currently buffered log messages.
 */
__syscall uint32_t log_buffered_cnt(void);

/** @brief Get number of independent logger sources (modules and instances)
 *
 * @param domain_id Domain ID.
 *
 * @return Number of sources.
 */
uint32_t log_src_cnt_get(uint32_t domain_id);


/** @brief Get name of the source (module or instance).
 *
 * @param domain_id Domain ID.
 * @param source_id Source ID.
 *
 * @return Source name or NULL if invalid arguments.
 */
const char *log_source_name_get(uint32_t domain_id, uint32_t source_id);

/** @brief Return number of domains present in the system.
 *
 * There will be at least one local domain.
 *
 * @return Number of domains.
 */
static inline uint8_t log_domains_count(void)
{
	return 1 + (IS_ENABLED(CONFIG_LOG_MULTIDOMAIN) ? z_log_ext_domain_count() : 0);
}

/** @brief Get name of the domain.
 *
 * @param domain_id Domain ID.
 *
 * @return Domain name.
 */
const char *log_domain_name_get(uint32_t domain_id);

/**
 * @brief Function for finding source ID based on source name.
 *
 * @param name Source name
 *
 * @return Source ID or negative number when source ID is not found.
 */
int log_source_id_get(const char *name);

/**
 * @brief Get source filter for the provided backend.
 *
 * @param backend	Backend instance.
 * @param domain_id	ID of the domain.
 * @param source_id	Source (module or instance) ID.
 * @param runtime	True for runtime filter or false for compiled in.
 *
 * @return		Severity level.
 */
uint32_t log_filter_get(struct log_backend const *const backend,
			uint32_t domain_id, int16_t source_id, bool runtime);

/**
 * @brief Set filter on given source for the provided backend.
 *
 * @param backend	Backend instance. NULL for all backends (and frontend).
 * @param domain_id	ID of the domain.
 * @param source_id	Source (module or instance) ID.
 * @param level		Severity level.
 *
 * @return Actual level set which may be limited by compiled level. If filter
 *	   was set for all backends then maximal level that was set is returned.
 */
__syscall uint32_t log_filter_set(struct log_backend const *const backend,
				  uint32_t domain_id, int16_t source_id,
				  uint32_t level);

/**
 * @brief Get source filter for the frontend.
 *
 * @param source_id	Source (module or instance) ID.
 * @param runtime	True for runtime filter or false for compiled in.
 *
 * @return		Severity level.
 */
uint32_t log_frontend_filter_get(int16_t source_id, bool runtime);

/**
 * @brief Set filter on given source for the frontend.
 *
 * @param source_id	Source (module or instance) ID.
 * @param level		Severity level.
 *
 * @return Actual level set which may be limited by compiled level.
 */
__syscall uint32_t log_frontend_filter_set(int16_t source_id, uint32_t level);

/**
 *
 * @brief Enable backend with initial maximum filtering level.
 *
 * @param backend	Backend instance.
 * @param ctx		User context.
 * @param level		Severity level.
 */
void log_backend_enable(struct log_backend const *const backend,
			void *ctx,
			uint32_t level);

/**
 *
 * @brief Disable backend.
 *
 * @param backend	Backend instance.
 */
void log_backend_disable(struct log_backend const *const backend);

/**
 * @brief Get backend by name.
 *
 * @param[in] backend_name Name of the backend as defined by the LOG_BACKEND_DEFINE.
 *
 * @retval Pointer to the backend instance if found, NULL if backend is not found.
 */
const struct log_backend *log_backend_get_by_name(const char *backend_name);

/** @brief Sets logging format for all active backends.
 *
 * @param log_type Log format.
 *
 * @retval Pointer to the last backend that failed, NULL for success.
 */
const struct log_backend *log_format_set_all_active_backends(size_t log_type);

/**
 * @brief Check if there is pending data to be processed by the logging subsystem.
 *
 * Function can be used to determine if all logs have been flushed. Function
 * returns false when deferred mode is not enabled.
 *
 * @retval true There is pending data.
 * @retval false No pending data to process.
 */
static inline bool log_data_pending(void)
{
	return IS_ENABLED(CONFIG_LOG_MODE_DEFERRED) ? z_log_msg_pending() : false;
}

/**
 * @brief Configure tag used to prefix each message.
 *
 * @param tag Tag.
 *
 * @retval 0 on successful operation.
 * @retval -ENOTSUP if feature is disabled.
 * @retval -ENOMEM if string is longer than the buffer capacity. Tag will be trimmed.
 */
int log_set_tag(const char *tag);

/**
 * @brief Get current memory usage.
 *
 * @param[out] buf_size Capacity of the buffer used for storing log messages.
 * @param[out] usage Number of bytes currently containing pending log messages.
 *
 * @retval -EINVAL if logging mode does not use the buffer.
 * @retval 0 successfully collected usage data.
 */
int log_mem_get_usage(uint32_t *buf_size, uint32_t *usage);

/**
 * @brief Get maximum memory usage.
 *
 * Requires CONFIG_LOG_MEM_UTILIZATION option.
 *
 * @param[out] max Maximum number of bytes used for pending log messages.
 *
 * @retval -EINVAL if logging mode does not use the buffer.
 * @retval -ENOTSUP if instrumentation is not enabled.
 * not been enabled.
 *
 * @retval 0 successfully collected usage data.
 */
int log_mem_get_max_usage(uint32_t *max);

#if defined(CONFIG_LOG) && !defined(CONFIG_LOG_MODE_MINIMAL)
#define LOG_CORE_INIT() log_core_init()
#define LOG_PANIC() log_panic()
#if defined(CONFIG_LOG_FRONTEND_ONLY)
#define LOG_INIT() 0
#define LOG_PROCESS() false
#else /* !CONFIG_LOG_FRONTEND_ONLY */
#define LOG_INIT() log_init()
#define LOG_PROCESS() log_process()
#endif /* !CONFIG_LOG_FRONTEND_ONLY */
#else
#define LOG_CORE_INIT() do { } while (false)
#define LOG_INIT() 0
#define LOG_PANIC() /* Empty */
#define LOG_PROCESS() false
#endif

#include <zephyr/syscalls/log_ctrl.h>

/**
 * @}
 */

#ifdef __cplusplus
}
#endif

#endif /* ZEPHYR_INCLUDE_LOGGING_LOG_CTRL_H_ */
