mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
esp_common: add generic check macros
Add four check maros: * ESP_RETURN_ON_ERROR() * ESP_GOTO_ON_ERROR() * ESP_RETURN_ON_FALSE() * ESP_GOTO_ON_FALSE() Also add a `xx_ISR` version for each of them, which can be used in ISR.
This commit is contained in:
parent
ffa93ed9ec
commit
6792024add
10
Kconfig
10
Kconfig
@ -279,6 +279,16 @@ mainmenu "Espressif IoT Development Framework Configuration"
|
||||
|
||||
endchoice # assertions
|
||||
|
||||
config COMPILER_OPTIMIZATION_CHECKS_SILENT
|
||||
bool "Disable messages in ESP_RETURN_ON_* and ESP_EXIT_ON_* macros"
|
||||
default n
|
||||
help
|
||||
If enabled, the error messages will be discarded in following check macros:
|
||||
- ESP_RETURN_ON_ERROR
|
||||
- ESP_EXIT_ON_ERROR
|
||||
- ESP_RETURN_ON_FALSE
|
||||
- ESP_EXIT_ON_FALSE
|
||||
|
||||
menuconfig COMPILER_HIDE_PATHS_MACROS
|
||||
bool "Replace ESP-IDF and project paths in binaries"
|
||||
default y
|
||||
|
188
components/esp_common/include/esp_check.h
Normal file
188
components/esp_common/include/esp_check.h
Normal file
@ -0,0 +1,188 @@
|
||||
// Copyright 2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// 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
|
||||
|
||||
// http://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 "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Macro which can be used to check the error code. If the code is not ESP_OK, it prints the message and returns.
|
||||
*/
|
||||
#if defined(CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT)
|
||||
#define ESP_RETURN_ON_ERROR(x, log_tag, format, ...) do { \
|
||||
esp_err_t err_rc_ = (x); \
|
||||
if (unlikely(err_rc_ != ESP_OK)) { \
|
||||
return err_rc_; \
|
||||
} \
|
||||
} while(0)
|
||||
#else
|
||||
#define ESP_RETURN_ON_ERROR(x, log_tag, format, ...) do { \
|
||||
esp_err_t err_rc_ = (x); \
|
||||
if (unlikely(err_rc_ != ESP_OK)) { \
|
||||
ESP_LOGE(log_tag, "%s(%d): " format, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
|
||||
return err_rc_; \
|
||||
} \
|
||||
} while(0)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* A version of ESP_RETURN_ON_ERROR() macro that can be called from ISR.
|
||||
*/
|
||||
#if defined(CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT)
|
||||
#define ESP_RETURN_ON_ERROR_ISR(x, log_tag, format, ...) do { \
|
||||
esp_err_t err_rc_ = (x); \
|
||||
if (unlikely(err_rc_ != ESP_OK)) { \
|
||||
return err_rc_; \
|
||||
} \
|
||||
} while(0)
|
||||
#else
|
||||
#define ESP_RETURN_ON_ERROR_ISR(x, log_tag, format, ...) do { \
|
||||
esp_err_t err_rc_ = (x); \
|
||||
if (unlikely(err_rc_ != ESP_OK)) { \
|
||||
ESP_EARLY_LOGE(log_tag, "%s(%d): " format, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
|
||||
return err_rc_; \
|
||||
} \
|
||||
} while(0)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Macro which can be used to check the error code. If the code is not ESP_OK, it prints the message,
|
||||
* sets the local variable 'ret' to the code, and then exits by jumping to 'goto_tag'.
|
||||
*/
|
||||
#if defined(CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT)
|
||||
#define ESP_GOTO_ON_ERROR(x, goto_tag, log_tag, format, ...) do { \
|
||||
esp_err_t err_rc_ = (x); \
|
||||
if (unlikely(err_rc_ != ESP_OK)) { \
|
||||
ret = err_rc_; \
|
||||
goto goto_tag; \
|
||||
} \
|
||||
} while(0)
|
||||
#else
|
||||
#define ESP_GOTO_ON_ERROR(x, goto_tag, log_tag, format, ...) do { \
|
||||
esp_err_t err_rc_ = (x); \
|
||||
if (unlikely(err_rc_ != ESP_OK)) { \
|
||||
ESP_LOGE(log_tag, "%s(%d): " format, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
|
||||
ret = err_rc_; \
|
||||
goto goto_tag; \
|
||||
} \
|
||||
} while(0)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* A version of ESP_GOTO_ON_ERROR() macro that can be called from ISR.
|
||||
*/
|
||||
#if defined(CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT)
|
||||
#define ESP_GOTO_ON_ERROR_ISR(x, goto_tag, log_tag, format, ...) do { \
|
||||
esp_err_t err_rc_ = (x); \
|
||||
if (unlikely(err_rc_ != ESP_OK)) { \
|
||||
ret = err_rc_; \
|
||||
goto goto_tag; \
|
||||
} \
|
||||
} while(0)
|
||||
#else
|
||||
#define ESP_GOTO_ON_ERROR_ISR(x, goto_tag, log_tag, format, ...) do { \
|
||||
esp_err_t err_rc_ = (x); \
|
||||
if (unlikely(err_rc_ != ESP_OK)) { \
|
||||
ESP_EARLY_LOGE(log_tag, "%s(%d): " format, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
|
||||
ret = err_rc_; \
|
||||
goto goto_tag; \
|
||||
} \
|
||||
} while(0)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Macro which can be used to check the condition. If the condition is not 'true', it prints the message
|
||||
* and returns with the supplied 'err_code'.
|
||||
*/
|
||||
#if defined(CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT)
|
||||
#define ESP_RETURN_ON_FALSE(a, err_code, log_tag, format, ...) do { \
|
||||
if (unlikely(!(a))) { \
|
||||
return err_code; \
|
||||
} \
|
||||
} while(0)
|
||||
#else
|
||||
#define ESP_RETURN_ON_FALSE(a, err_code, log_tag, format, ...) do { \
|
||||
if (unlikely(!(a))) { \
|
||||
ESP_LOGE(log_tag, "%s(%d): " format, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
|
||||
return err_code; \
|
||||
} \
|
||||
} while(0)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* A version of ESP_RETURN_ON_FALSE() macro that can be called from ISR.
|
||||
*/
|
||||
#if defined(CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT)
|
||||
#define ESP_RETURN_ON_FALSE_ISR(a, err_code, log_tag, format, ...) do { \
|
||||
if (unlikely(!(a))) { \
|
||||
return err_code; \
|
||||
} \
|
||||
} while(0)
|
||||
#else
|
||||
#define ESP_RETURN_ON_FALSE_ISR(a, err_code, log_tag, format, ...) do { \
|
||||
if (unlikely(!(a))) { \
|
||||
ESP_EARLY_LOGE(log_tag, "%s(%d): " format, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
|
||||
return err_code; \
|
||||
} \
|
||||
} while(0)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Macro which can be used to check the condition. If the condition is not 'true', it prints the message,
|
||||
* sets the local variable 'ret' to the supplied 'err_code', and then exits by jumping to 'goto_tag'.
|
||||
*/
|
||||
#if defined(CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT)
|
||||
#define ESP_GOTO_ON_FALSE(a, err_code, goto_tag, log_tag, format, ...) do { \
|
||||
if (unlikely(!(a))) { \
|
||||
ret = err_code; \
|
||||
goto goto_tag; \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
#define ESP_GOTO_ON_FALSE(a, err_code, goto_tag, log_tag, format, ...) do { \
|
||||
if (unlikely(!(a))) { \
|
||||
ESP_LOGE(log_tag, "%s(%d): " format, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
|
||||
ret = err_code; \
|
||||
goto goto_tag; \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* A version of ESP_GOTO_ON_FALSE() macro that can be called from ISR.
|
||||
*/
|
||||
#if defined(CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT)
|
||||
#define ESP_GOTO_ON_FALSE_ISR(a, err_code, goto_tag, log_tag, format, ...) do { \
|
||||
if (unlikely(!(a))) { \
|
||||
ret = err_code; \
|
||||
goto goto_tag; \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
#define ESP_GOTO_ON_FALSE_ISR(a, err_code, goto_tag, log_tag, format, ...) do { \
|
||||
if (unlikely(!(a))) { \
|
||||
ESP_EARLY_LOGE(log_tag, "%s(%d): " format, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
|
||||
ret = err_code; \
|
||||
goto goto_tag; \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -16,6 +16,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include "esp_compiler.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -104,21 +105,21 @@ void _esp_error_check_failed_without_abort(esp_err_t rc, const char *file, int l
|
||||
*/
|
||||
#ifdef NDEBUG
|
||||
#define ESP_ERROR_CHECK(x) do { \
|
||||
esp_err_t __err_rc = (x); \
|
||||
(void) sizeof(__err_rc); \
|
||||
esp_err_t err_rc_ = (x); \
|
||||
(void) sizeof(err_rc_); \
|
||||
} while(0)
|
||||
#elif defined(CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT)
|
||||
#define ESP_ERROR_CHECK(x) do { \
|
||||
esp_err_t __err_rc = (x); \
|
||||
if (__err_rc != ESP_OK) { \
|
||||
esp_err_t err_rc_ = (x); \
|
||||
if (unlikely(err_rc_ != ESP_OK)) { \
|
||||
abort(); \
|
||||
} \
|
||||
} while(0)
|
||||
#else
|
||||
#define ESP_ERROR_CHECK(x) do { \
|
||||
esp_err_t __err_rc = (x); \
|
||||
if (__err_rc != ESP_OK) { \
|
||||
_esp_error_check_failed(__err_rc, __FILE__, __LINE__, \
|
||||
esp_err_t err_rc_ = (x); \
|
||||
if (unlikely(err_rc_ != ESP_OK)) { \
|
||||
_esp_error_check_failed(err_rc_, __FILE__, __LINE__, \
|
||||
__ASSERT_FUNC, #x); \
|
||||
} \
|
||||
} while(0)
|
||||
@ -131,17 +132,17 @@ void _esp_error_check_failed_without_abort(esp_err_t rc, const char *file, int l
|
||||
*/
|
||||
#ifdef NDEBUG
|
||||
#define ESP_ERROR_CHECK_WITHOUT_ABORT(x) ({ \
|
||||
esp_err_t __err_rc = (x); \
|
||||
__err_rc; \
|
||||
esp_err_t err_rc_ = (x); \
|
||||
err_rc_; \
|
||||
})
|
||||
#else
|
||||
#define ESP_ERROR_CHECK_WITHOUT_ABORT(x) ({ \
|
||||
esp_err_t __err_rc = (x); \
|
||||
if (__err_rc != ESP_OK) { \
|
||||
_esp_error_check_failed_without_abort(__err_rc, __FILE__, __LINE__, \
|
||||
__ASSERT_FUNC, #x); \
|
||||
esp_err_t err_rc_ = (x); \
|
||||
if (unlikely(err_rc_ != ESP_OK)) { \
|
||||
_esp_error_check_failed_without_abort(err_rc_, __FILE__, __LINE__, \
|
||||
__ASSERT_FUNC, #x); \
|
||||
} \
|
||||
__err_rc; \
|
||||
err_rc_; \
|
||||
})
|
||||
#endif //NDEBUG
|
||||
|
||||
|
@ -289,6 +289,8 @@ INPUT = \
|
||||
$(IDF_PATH)/components/esp_ringbuf/include/freertos/ringbuf.h \
|
||||
### Helper functions for error codes
|
||||
$(IDF_PATH)/components/esp_common/include/esp_err.h \
|
||||
### Check macros
|
||||
$(IDF_PATH)/components/esp_common/include/esp_check.h \
|
||||
### System APIs
|
||||
$(IDF_PATH)/components/esp_system/include/esp_system.h \
|
||||
### Modbus controller component header file
|
||||
|
@ -68,6 +68,71 @@ Error message will typically look like this::
|
||||
|
||||
- Finally, backtrace is printed. This is part of panic handler output common to all fatal errors. See :doc:`Fatal Errors <fatal-errors>` for more information about the backtrace.
|
||||
|
||||
.. _esp-error-check-without-abort-macro:
|
||||
|
||||
``ESP_ERROR_CHECK_WITHOUT_ABORT`` macro
|
||||
---------------------------------------
|
||||
|
||||
:cpp:func:`ESP_ERROR_CHECK_WITHOUT_ABORT` macro serves similar purpose as ``ESP_ERROR_CHECK``, except that it won't call ``abort()``.
|
||||
|
||||
.. _esp-return-on-error-macro:
|
||||
|
||||
``ESP_RETURN_ON_ERROR`` macro
|
||||
-----------------------------
|
||||
|
||||
:cpp:func:`ESP_RETURN_ON_ERROR` macro checks the error code, if the error code is not equal :c:macro:`ESP_OK`, it prints the message and returns.
|
||||
|
||||
.. _esp-goto-on-error-macro:
|
||||
|
||||
``ESP_GOTO_ON_ERROR`` macro
|
||||
---------------------------
|
||||
|
||||
:cpp:func:`ESP_GOTO_ON_ERROR` macro checks the error code, if the error code is not equal :c:macro:`ESP_OK`, it prints the message, sets the local variable `ret` to the code, and then exits by jumping to `goto_tag`.
|
||||
|
||||
.. _esp-return-on-false-macro:
|
||||
|
||||
``ESP_RETURN_ON_FALSE`` macro
|
||||
-----------------------------
|
||||
|
||||
:cpp:func:`ESP_RETURN_ON_FALSE` macro checks the condition, if the condition is not equal `true`, it prints the message and returns with the supplied `err_code`.
|
||||
|
||||
.. _esp-goto-on-false-macro:
|
||||
|
||||
``ESP_GOTO_ON_FALSE`` macro
|
||||
---------------------------
|
||||
|
||||
:cpp:func:`ESP_GOTO_ON_FALSE` macro checks the condition, if the condition is not equal `true`, it prints the message, sets the local variable `ret` to the supplied `err_code`, and then exits by jumping to `goto_tag`.
|
||||
|
||||
.. _check_macros_examples:
|
||||
|
||||
``CHECK MACROS Examples``
|
||||
-------------------------
|
||||
|
||||
Some examples::
|
||||
|
||||
static const char* TAG = "Test";
|
||||
|
||||
esp_err_t test_func(void)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
ESP_ERROR_CHECK(x); // err message printed if `x` is not `ESP_OK`, and then `abort()`.
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(x); // err message printed if `x` is not `ESP_OK`, without `abort()`.
|
||||
ESP_RETURN_ON_ERROR(x, TAG, "fail reason 1"); // err message printed if `x` is not `ESP_OK`, and then function returns with code `x`.
|
||||
ESP_GOTO_ON_ERROR(x, err, TAG, "fail reason 2"); // err message printed if `x` is not `ESP_OK`, `ret` is set to `x`, and then jumps to `err`.
|
||||
ESP_RETURN_ON_FALSE(a, err_code, TAG, "fail reason 3"); // err message printed if `a` is not `true`, and then function returns with code `err_code`.
|
||||
ESP_GOTO_ON_FALSE(a, err_code, err, TAG, "fail reason 4"); // err message printed if `a` is not `true`, `ret` is set to `err_code`, and then jumps to `err`.
|
||||
|
||||
err:
|
||||
// clean up
|
||||
return ret;
|
||||
}
|
||||
|
||||
.. note::
|
||||
|
||||
If the option :ref:`CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT` in Kconfig is enabled, the err message will be discarded, while the other action works as is.
|
||||
|
||||
The ``ESP_RETURN_XX`` and ``ESP_GOTO_xx`` macros can't be called from ISR. While there are ``xx_ISR`` versions for each of them, e.g., `ESP_RETURN_ON_ERROR_ISR`, these macros could be used in ISR.
|
||||
|
||||
Error handling patterns
|
||||
-----------------------
|
||||
|
@ -69,6 +69,71 @@ ESP-IDF 中大多数函数会返回 :cpp:type:`esp_err_t` 类型的错误码,
|
||||
|
||||
.. note:: 如果使用 :doc:`IDF monitor <tools/idf-monitor>`, 则最后一行回溯结果中的地址将会被替换为相应的文件名和行号。
|
||||
|
||||
.. _esp-error-check-without-abort-macro:
|
||||
|
||||
``ESP_ERROR_CHECK_WITHOUT_ABORT`` 宏
|
||||
------------------------------------
|
||||
|
||||
宏 :cpp:func:`ESP_ERROR_CHECK_WITHOUT_ABORT` 的功能和 ``ESP_ERROR_CHECK`` 类似, 不同之处在于它不会调用 ``abort()``.
|
||||
|
||||
.. _esp-return-on-error-macro:
|
||||
|
||||
``ESP_RETURN_ON_ERROR`` 宏
|
||||
--------------------------
|
||||
|
||||
宏 :cpp:func:`ESP_RETURN_ON_ERROR` 用于错误码检查, 如果错误码不等于 :c:macro:`ESP_OK`, 该宏会打印错误信息,并使原函数立刻返回。
|
||||
|
||||
.. _esp-goto-on-error-macro:
|
||||
|
||||
``ESP_GOTO_ON_ERROR`` 宏
|
||||
------------------------
|
||||
|
||||
宏 :cpp:func:`ESP_GOTO_ON_ERROR` 用于错误码检查, 如果错误码不等于 :c:macro:`ESP_OK`, 该宏会打印错误信息,将局部变量 `ret` 赋值为该错误码, 并使原函数跳转至给定的 `goto_tag`.
|
||||
|
||||
.. _esp-return-on-false-macro:
|
||||
|
||||
``ESP_RETURN_ON_FALSE`` 宏
|
||||
--------------------------
|
||||
|
||||
宏 :cpp:func:`ESP_RETURN_ON_FALSE` 用于条件检查, 如果给定条件不等于 `true`, 该宏会打印错误信息,并使原函数立刻返回,返回值为给定的 `err_code`.
|
||||
|
||||
.. _esp-goto-on-false-macro:
|
||||
|
||||
``ESP_GOTO_ON_FALSE`` 宏
|
||||
------------------------
|
||||
|
||||
宏 :cpp:func:`ESP_GOTO_ON_FALSE` 用于条件检查, 如果给定条件不等于 `true`, 该宏会打印错误信息,将局部变量 `ret` 赋值为给定的 `err_code`, 并使原函数跳转至给定的 `goto_tag`.
|
||||
|
||||
.. _check_macros_examples:
|
||||
|
||||
``CHECK 宏使用示例``
|
||||
-------------------------
|
||||
|
||||
示例::
|
||||
|
||||
static const char* TAG = "Test";
|
||||
|
||||
esp_err_t test_func(void)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
ESP_ERROR_CHECK(x); // err message printed if `x` is not `ESP_OK`, and then `abort()`.
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(x); // err message printed if `x` is not `ESP_OK`, without `abort()`.
|
||||
ESP_RETURN_ON_ERROR(x, TAG, "fail reason 1"); // err message printed if `x` is not `ESP_OK`, and then function returns with code `x`.
|
||||
ESP_GOTO_ON_ERROR(x, err, TAG, "fail reason 2"); // err message printed if `x` is not `ESP_OK`, `ret` is set to `x`, and then jumps to `err`.
|
||||
ESP_RETURN_ON_FALSE(a, err_code, TAG, "fail reason 3"); // err message printed if `a` is not `true`, and then function returns with code `err_code`.
|
||||
ESP_GOTO_ON_FALSE(a, err_code, err, TAG, "fail reason 4"); // err message printed if `a` is not `true`, `ret` is set to `err_code`, and then jumps to `err`.
|
||||
|
||||
err:
|
||||
// clean up
|
||||
return ret;
|
||||
}
|
||||
|
||||
.. note::
|
||||
|
||||
如果 Kconfig 中的 :ref:`CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT` 选项被打开, CHECK 宏将不会打印错误信息,其他功能不变。
|
||||
|
||||
``ESP_RETURN_xx`` 和 ``ESP_GOTO_xx`` 宏不可以在中断服务程序里被调用。如需要在中断中使用类似功能,请使用 ``xx_ISR`` 宏,如 ``ESP_RETURN_ON_ERROR_ISR`` 等。
|
||||
|
||||
错误处理模式
|
||||
------------
|
||||
|
Loading…
Reference in New Issue
Block a user