/* * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #pragma once #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif /** * @brief Callback to write log to diagnostics storage */ typedef esp_err_t (*esp_diag_log_write_cb_t)(void *data, size_t len, void *priv_data); /** * @brief Diagnostics log configurations */ typedef struct { esp_diag_log_write_cb_t write_cb; /*!< Callback function to write diagnostics data */ void *cb_arg; /*!< User data to pass in callback function */ } esp_diag_log_config_t; /** * @brief Supported log types in diagnostics */ typedef enum { ESP_DIAG_LOG_TYPE_ERROR = 1 << 0, /*!< Diagnostics log type error */ ESP_DIAG_LOG_TYPE_WARNING = 1 << 1, /*!< Diagnostics log type warning */ ESP_DIAG_LOG_TYPE_EVENT = 1 << 2, /*!< Diagnostics log type event */ } esp_diag_log_type_t; /** * @brief Log argument data types */ typedef enum { ARG_TYPE_CHAR, /*!< Argument type (char) */ ARG_TYPE_SHORT, /*!< Argument type (short) */ ARG_TYPE_INT, /*!< Argument type (int) */ ARG_TYPE_L, /*!< Argument type (long) */ ARG_TYPE_LL, /*!< Argument type (long long) */ ARG_TYPE_INTMAX, /*!< Argument type (intmax_t) */ ARG_TYPE_PTRDIFF, /*!< Argument type (ptrdiff_t) */ ARG_TYPE_UCHAR, /*!< Argument type (unsigned char) */ ARG_TYPE_USHORT, /*!< Argument type (unsigned short) */ ARG_TYPE_UINT, /*!< Argument type (unsigned int) */ ARG_TYPE_UL, /*!< Argument type (unsigned long) */ ARG_TYPE_ULL, /*!< Argument type (unsigned long long) */ ARG_TYPE_UINTMAX, /*!< Argument type (uintmax_t) */ ARG_TYPE_SIZE, /*!< Argument type (size_t) */ ARG_TYPE_DOUBLE, /*!< Argument type (double) */ ARG_TYPE_LDOUBLE, /*!< Argument type (long double) */ ARG_TYPE_STR, /*!< Argument type (char *) */ ARG_TYPE_INVALID, /*!< Argument type invalid */ } esp_diag_arg_type_t; /** * @brief Log argument data value */ typedef union { char c; /*!< Value of type signed char */ short s; /*!< Value of type signed short */ int i; /*!< Value of type signed integer */ long l; /*!< Value of type signed long */ long long ll; /*!< Value of type signed long long */ intmax_t imx; /*!< Value of type intmax_t */ ptrdiff_t ptrdiff; /*!< Value of type ptrdiff_t */ unsigned char uc; /*!< Value of type unsigned char */ unsigned short us; /*!< Value of type unsigned short */ unsigned int u; /*!< Value of type unsigned integer */ unsigned long ul; /*!< Value of type unsigned long */ unsigned long long ull; /*!< Value of type unsigned long long */ uintmax_t umx; /*!< Value of type uintmax_t */ size_t sz; /*!< Value of type size_t */ double d; /*!< Value of type double */ long double ld; /*!< Value of type long double */ char *str; /*!< value of type string */ } esp_diag_arg_value_t; /** * @brief Diagnostics data point type */ typedef enum { ESP_DIAG_DATA_PT_METRICS, /*!< Data point of type metrics */ ESP_DIAG_DATA_PT_VARIABLE, /*!< Data point of type variable */ } esp_diag_data_pt_type_t; /** * @brief Diagnostics data types */ typedef enum { ESP_DIAG_DATA_TYPE_BOOL, /*!< Data type boolean */ ESP_DIAG_DATA_TYPE_INT, /*!< Data type integer */ ESP_DIAG_DATA_TYPE_UINT, /*!< Data type unsigned integer */ ESP_DIAG_DATA_TYPE_FLOAT, /*!< Data type float */ ESP_DIAG_DATA_TYPE_STR, /*!< Data type string */ ESP_DIAG_DATA_TYPE_IPv4, /*!< Data type IPv4 address */ ESP_DIAG_DATA_TYPE_MAC, /*!< Data type MAC address */ ESP_DIAG_DATA_TYPE_NULL, /*!< No type */ ESP_DIAG_DATA_TYPE_MAX, /*!< Max type */ } esp_diag_data_type_t; /** * @brief Diagnostics log data structure */ typedef struct { esp_diag_log_type_t type; /*!< Type of diagnostics log */ uint32_t pc; /*!< Program Counter */ uint64_t timestamp; /*!< If NTP sync enabled then POSIX time, otherwise relative time since bootup in microseconds */ char tag[16]; /*!< Tag of log message */ void *msg_ptr; /*!< Address of err/warn/event message in rodata */ uint8_t msg_args[CONFIG_DIAG_LOG_MSG_ARG_MAX_SIZE]; /*!< Arguments of log message */ uint8_t msg_args_len; /*!< Length of argument */ char task_name[CONFIG_FREERTOS_MAX_TASK_NAME_LEN]; /*!< Task name */ } esp_diag_log_data_t; /** * @brief Device information structure */ #define DIAG_HEX_SHA_SIZE 16 /* Length of ELF SHA as HEX string*/ #define DIAG_SHA_SIZE (DIAG_HEX_SHA_SIZE / 2) /* Length of ELF SHA as raw bytes*/ typedef struct { uint32_t chip_model; /*!< Chip model */ uint32_t chip_rev; /*!< Chip revision */ uint32_t reset_reason; /*!< Reset reason */ char app_version[32]; /*!< Application version */ char project_name[32]; /*!< Project name */ char app_elf_sha256[DIAG_HEX_SHA_SIZE + 1]; /*!< SHA256 of application elf */ } esp_diag_device_info_t; /** * @brief Task backtrace structure */ typedef struct { uint32_t bt[16]; /*!< Backtrace (array of PC) */ uint32_t depth; /*!< Number of backtrace entries */ bool corrupted; /*!< Status flag for backtrace is corrupt or not */ } esp_diag_task_bt_t; /** * @brief Task information structure */ typedef struct { char name[CONFIG_FREERTOS_MAX_TASK_NAME_LEN]; /*!< Task name */ uint32_t state; /*!< Task state */ uint32_t high_watermark; /*!< Task high watermark */ #ifndef CONFIG_IDF_TARGET_ARCH_RISCV esp_diag_task_bt_t bt_info; /*!< Backtrace of the task */ #endif /* !CONFIG_IDF_TARGET_ARCH_RISCV */ } esp_diag_task_info_t; /** * @brief Structure for diagnostics data point */ typedef struct { uint16_t type; /*!< Metrics or Variable */ uint16_t data_type; /*!< Data type */ #ifndef CONFIG_ESP_INSIGHTS_META_VERSION_10 char tag[16]; /*!< TAG */ #endif char key[16]; /*!< Key */ uint64_t ts; /*!< Timestamp */ union { bool b; /*!< Value for boolean data type */ int32_t i; /*!< Value for integer data type */ uint32_t u; /*!< Value for unsigned integer data type */ float f; /*!< Value for float data type */ uint32_t ipv4; /*!< Value for the IPv4 address */ uint8_t mac[6]; /*!< Value for the MAC address */ } value; } esp_diag_data_pt_t; /** * @brief Structure for string data type diagnostics data point */ typedef struct { uint16_t type; /*!< Metrics or Variable */ uint16_t data_type; /*!< Data type */ #ifndef CONFIG_ESP_INSIGHTS_META_VERSION_10 char tag[16]; /*!< TAG */ #endif char key[16]; /*!< Key */ uint64_t ts; /*!< Timestamp */ union { char str[32]; /*!< Value for string data type */ } value; } esp_diag_str_data_pt_t; /** * @brief Initialize diagnostics log hook * * @param[in] config Pointer to a config structure of type \ref esp_diag_log_config_t * * @return ESP_OK if successful, appropriate error code otherwise. */ esp_err_t esp_diag_log_hook_init(esp_diag_log_config_t *config); /** * @brief Enable the diagnostics log hook for provided log type * * @param[in] type Log type to enable, can be the bitwise OR of types from \ref esp_diag_log_type_t */ void esp_diag_log_hook_enable(uint32_t type); /** * @brief Disable the diagnostics log hook for provided log type * * @param[in] type Log type to disable, can be the bitwise OR of types from \ref esp_diag_log_type_t * */ void esp_diag_log_hook_disable(uint32_t type); /** * @brief Add diagnostics event * * @param[in] tag The tag of message * @param[in] format Message format * @param[in] ... Variable arguments * * @return ESP_OK if successful, appropriate error code otherwise. * * @note This function is not intended to be used directly, Instead, use macro \ref ESP_DIAG_EVENT */ esp_err_t esp_diag_log_event(const char *tag, const char *format, ...) __attribute__ ((format (printf, 2, 3))); /** * @brief Macro to add the custom event * * @param[in] tag tag of the event * @param[in] format format of the event * @param[in] ... Variable arguments */ #define ESP_DIAG_EVENT(tag, format, ...) \ { \ esp_diag_log_event(tag, "EV (%" PRIu32 ") %s: " format, esp_log_timestamp(), tag, ##__VA_ARGS__); \ ESP_LOGI(tag, format, ##__VA_ARGS__); \ } /** * @brief Get the device information for diagnostics * * @param[out] device_info Pointer to device_info structure of type \ref esp_diag_device_info_t * * @return ESP_OK on success * @return ESP_ERR_INVALID_ARG if device_info is NULL */ esp_err_t esp_diag_device_info_get(esp_diag_device_info_t *device_info); /** * @brief Get the timestamp * * This function returns POSIX time if NTP sync is enabled * otherwise returns time since bootup in microseconds * * @return timestamp */ uint64_t esp_diag_timestamp_get(void); /** * @brief Get backtrace and some more details of all tasks in system * * @note On device backtrace parsing not available on RISC-V boards (ESP32C3) * * @param[out] tasks Array to store task info * @param[in] size Size of array, If size is less than the number of tasks in system, * then info of size tasks is filled in array * * @return Number of task info filled in array * * @note Allocate enough memory to store all tasks, * Use uxTaskGetNumberOfTasks() to get number of tasks in system */ uint32_t esp_diag_task_snapshot_get(esp_diag_task_info_t *tasks, size_t size); /** * @brief Dump backtrace and some more details of all tasks * in system to console using \ref ESP_DIAG_EVENT */ void esp_diag_task_snapshot_dump(void); /** * @brief Get CRC of diagnostics metadata * * @return crc */ uint32_t esp_diag_meta_crc_get(void); /** * @brief Get CRC of diagnostics data structures' size * * @return crc */ uint32_t esp_diag_data_size_get_crc(void); /** * @brief Convenience API for ingesting log data into diagnostics when esp_log_writev() is externally wrapped. * This API should be called from __wrap_esp_log_writev(). \see CONFIG_DIAG_USE_EXTERNAL_LOG_WRAP. * * @param[in] level Log level * @param[in] tag Tag of the log * @param[in] format Format of the log * @param[in] v Variable argument list * * @note The Diagnostics component wraps the esp_log_write() and esp_log_writev() APIs using the `--wrap` GCC option * to collect logs. If another component intends to wrap the logging APIs, enable the configuration option * CONFIG_DIAG_USE_EXTERNAL_LOG_WRAP. This will prevent the Diagnostics component from wrapping the logging APIs. * To enable log diagnostics in such case, call the esp_diag_log_writev() and esp_diag_log_write() APIs within * their respective externally wrapped APIs. * * @note Avoid calling this API explicitly unless there is an use case as the one described above. */ void esp_diag_log_writev(esp_log_level_t level, const char *tag, const char *format, va_list v); /** * @brief Convenience API for ingesting log data into diagnostics when esp_log_write() is externally wrapped. * This API should be called from __wrap_esp_log_write(). \see CONFIG_DIAG_USE_EXTERNAL_LOG_WRAP. * * @param[in] level Log level * @param[in] tag Tag of the log * @param[in] format Format of the log * @param[in] v variable argument list * * @note Please see notes from \see esp_diag_log_writev() */ void esp_diag_log_write(esp_log_level_t level, const char *tag, const char *format, va_list v); #ifdef __cplusplus } #endif