Explorar el Código

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.
Shu Chen hace 5 años
padre
commit
6792024add

+ 10 - 0
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 - 0
components/esp_common/include/esp_check.h

@@ -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

+ 15 - 14
components/esp_common/include/esp_err.h

@@ -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
 

+ 2 - 0
docs/doxygen/Doxyfile_common

@@ -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

+ 65 - 0
docs/en/api-guides/error-handling.rst

@@ -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
 -----------------------

+ 65 - 0
docs/zh_CN/api-guides/error-handling.rst

@@ -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`` 等。
 
 错误处理模式
 ------------