Skip to content

Commit 793771e

Browse files
committed
Merge branch 'feature/esp_error_check_return' into 'master'
esp_common: add generic check macros Closes IDF-2271 See merge request espressif/esp-idf!12602
2 parents 8ec8f61 + 6792024 commit 793771e

File tree

6 files changed

+345
-14
lines changed

6 files changed

+345
-14
lines changed

Kconfig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,16 @@ mainmenu "Espressif IoT Development Framework Configuration"
279279

280280
endchoice # assertions
281281

282+
config COMPILER_OPTIMIZATION_CHECKS_SILENT
283+
bool "Disable messages in ESP_RETURN_ON_* and ESP_EXIT_ON_* macros"
284+
default n
285+
help
286+
If enabled, the error messages will be discarded in following check macros:
287+
- ESP_RETURN_ON_ERROR
288+
- ESP_EXIT_ON_ERROR
289+
- ESP_RETURN_ON_FALSE
290+
- ESP_EXIT_ON_FALSE
291+
282292
menuconfig COMPILER_HIDE_PATHS_MACROS
283293
bool "Replace ESP-IDF and project paths in binaries"
284294
default y
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
// Copyright 2021 Espressif Systems (Shanghai) PTE LTD
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
#pragma once
15+
16+
#include "esp_err.h"
17+
#include "esp_log.h"
18+
19+
#ifdef __cplusplus
20+
extern "C" {
21+
#endif
22+
23+
/**
24+
* Macro which can be used to check the error code. If the code is not ESP_OK, it prints the message and returns.
25+
*/
26+
#if defined(CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT)
27+
#define ESP_RETURN_ON_ERROR(x, log_tag, format, ...) do { \
28+
esp_err_t err_rc_ = (x); \
29+
if (unlikely(err_rc_ != ESP_OK)) { \
30+
return err_rc_; \
31+
} \
32+
} while(0)
33+
#else
34+
#define ESP_RETURN_ON_ERROR(x, log_tag, format, ...) do { \
35+
esp_err_t err_rc_ = (x); \
36+
if (unlikely(err_rc_ != ESP_OK)) { \
37+
ESP_LOGE(log_tag, "%s(%d): " format, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
38+
return err_rc_; \
39+
} \
40+
} while(0)
41+
#endif
42+
43+
/**
44+
* A version of ESP_RETURN_ON_ERROR() macro that can be called from ISR.
45+
*/
46+
#if defined(CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT)
47+
#define ESP_RETURN_ON_ERROR_ISR(x, log_tag, format, ...) do { \
48+
esp_err_t err_rc_ = (x); \
49+
if (unlikely(err_rc_ != ESP_OK)) { \
50+
return err_rc_; \
51+
} \
52+
} while(0)
53+
#else
54+
#define ESP_RETURN_ON_ERROR_ISR(x, log_tag, format, ...) do { \
55+
esp_err_t err_rc_ = (x); \
56+
if (unlikely(err_rc_ != ESP_OK)) { \
57+
ESP_EARLY_LOGE(log_tag, "%s(%d): " format, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
58+
return err_rc_; \
59+
} \
60+
} while(0)
61+
#endif
62+
63+
/**
64+
* Macro which can be used to check the error code. If the code is not ESP_OK, it prints the message,
65+
* sets the local variable 'ret' to the code, and then exits by jumping to 'goto_tag'.
66+
*/
67+
#if defined(CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT)
68+
#define ESP_GOTO_ON_ERROR(x, goto_tag, log_tag, format, ...) do { \
69+
esp_err_t err_rc_ = (x); \
70+
if (unlikely(err_rc_ != ESP_OK)) { \
71+
ret = err_rc_; \
72+
goto goto_tag; \
73+
} \
74+
} while(0)
75+
#else
76+
#define ESP_GOTO_ON_ERROR(x, goto_tag, log_tag, format, ...) do { \
77+
esp_err_t err_rc_ = (x); \
78+
if (unlikely(err_rc_ != ESP_OK)) { \
79+
ESP_LOGE(log_tag, "%s(%d): " format, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
80+
ret = err_rc_; \
81+
goto goto_tag; \
82+
} \
83+
} while(0)
84+
#endif
85+
86+
/**
87+
* A version of ESP_GOTO_ON_ERROR() macro that can be called from ISR.
88+
*/
89+
#if defined(CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT)
90+
#define ESP_GOTO_ON_ERROR_ISR(x, goto_tag, log_tag, format, ...) do { \
91+
esp_err_t err_rc_ = (x); \
92+
if (unlikely(err_rc_ != ESP_OK)) { \
93+
ret = err_rc_; \
94+
goto goto_tag; \
95+
} \
96+
} while(0)
97+
#else
98+
#define ESP_GOTO_ON_ERROR_ISR(x, goto_tag, log_tag, format, ...) do { \
99+
esp_err_t err_rc_ = (x); \
100+
if (unlikely(err_rc_ != ESP_OK)) { \
101+
ESP_EARLY_LOGE(log_tag, "%s(%d): " format, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
102+
ret = err_rc_; \
103+
goto goto_tag; \
104+
} \
105+
} while(0)
106+
#endif
107+
108+
/**
109+
* Macro which can be used to check the condition. If the condition is not 'true', it prints the message
110+
* and returns with the supplied 'err_code'.
111+
*/
112+
#if defined(CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT)
113+
#define ESP_RETURN_ON_FALSE(a, err_code, log_tag, format, ...) do { \
114+
if (unlikely(!(a))) { \
115+
return err_code; \
116+
} \
117+
} while(0)
118+
#else
119+
#define ESP_RETURN_ON_FALSE(a, err_code, log_tag, format, ...) do { \
120+
if (unlikely(!(a))) { \
121+
ESP_LOGE(log_tag, "%s(%d): " format, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
122+
return err_code; \
123+
} \
124+
} while(0)
125+
#endif
126+
127+
/**
128+
* A version of ESP_RETURN_ON_FALSE() macro that can be called from ISR.
129+
*/
130+
#if defined(CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT)
131+
#define ESP_RETURN_ON_FALSE_ISR(a, err_code, log_tag, format, ...) do { \
132+
if (unlikely(!(a))) { \
133+
return err_code; \
134+
} \
135+
} while(0)
136+
#else
137+
#define ESP_RETURN_ON_FALSE_ISR(a, err_code, log_tag, format, ...) do { \
138+
if (unlikely(!(a))) { \
139+
ESP_EARLY_LOGE(log_tag, "%s(%d): " format, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
140+
return err_code; \
141+
} \
142+
} while(0)
143+
#endif
144+
145+
/**
146+
* Macro which can be used to check the condition. If the condition is not 'true', it prints the message,
147+
* sets the local variable 'ret' to the supplied 'err_code', and then exits by jumping to 'goto_tag'.
148+
*/
149+
#if defined(CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT)
150+
#define ESP_GOTO_ON_FALSE(a, err_code, goto_tag, log_tag, format, ...) do { \
151+
if (unlikely(!(a))) { \
152+
ret = err_code; \
153+
goto goto_tag; \
154+
} \
155+
} while (0)
156+
#else
157+
#define ESP_GOTO_ON_FALSE(a, err_code, goto_tag, log_tag, format, ...) do { \
158+
if (unlikely(!(a))) { \
159+
ESP_LOGE(log_tag, "%s(%d): " format, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
160+
ret = err_code; \
161+
goto goto_tag; \
162+
} \
163+
} while (0)
164+
#endif
165+
166+
/**
167+
* A version of ESP_GOTO_ON_FALSE() macro that can be called from ISR.
168+
*/
169+
#if defined(CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT)
170+
#define ESP_GOTO_ON_FALSE_ISR(a, err_code, goto_tag, log_tag, format, ...) do { \
171+
if (unlikely(!(a))) { \
172+
ret = err_code; \
173+
goto goto_tag; \
174+
} \
175+
} while (0)
176+
#else
177+
#define ESP_GOTO_ON_FALSE_ISR(a, err_code, goto_tag, log_tag, format, ...) do { \
178+
if (unlikely(!(a))) { \
179+
ESP_EARLY_LOGE(log_tag, "%s(%d): " format, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
180+
ret = err_code; \
181+
goto goto_tag; \
182+
} \
183+
} while (0)
184+
#endif
185+
186+
#ifdef __cplusplus
187+
}
188+
#endif

components/esp_common/include/esp_err.h

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <stdint.h>
1717
#include <stdio.h>
1818
#include <assert.h>
19+
#include "esp_compiler.h"
1920

2021
#ifdef __cplusplus
2122
extern "C" {
@@ -104,21 +105,21 @@ void _esp_error_check_failed_without_abort(esp_err_t rc, const char *file, int l
104105
*/
105106
#ifdef NDEBUG
106107
#define ESP_ERROR_CHECK(x) do { \
107-
esp_err_t __err_rc = (x); \
108-
(void) sizeof(__err_rc); \
108+
esp_err_t err_rc_ = (x); \
109+
(void) sizeof(err_rc_); \
109110
} while(0)
110111
#elif defined(CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT)
111112
#define ESP_ERROR_CHECK(x) do { \
112-
esp_err_t __err_rc = (x); \
113-
if (__err_rc != ESP_OK) { \
113+
esp_err_t err_rc_ = (x); \
114+
if (unlikely(err_rc_ != ESP_OK)) { \
114115
abort(); \
115116
} \
116117
} while(0)
117118
#else
118119
#define ESP_ERROR_CHECK(x) do { \
119-
esp_err_t __err_rc = (x); \
120-
if (__err_rc != ESP_OK) { \
121-
_esp_error_check_failed(__err_rc, __FILE__, __LINE__, \
120+
esp_err_t err_rc_ = (x); \
121+
if (unlikely(err_rc_ != ESP_OK)) { \
122+
_esp_error_check_failed(err_rc_, __FILE__, __LINE__, \
122123
__ASSERT_FUNC, #x); \
123124
} \
124125
} while(0)
@@ -131,17 +132,17 @@ void _esp_error_check_failed_without_abort(esp_err_t rc, const char *file, int l
131132
*/
132133
#ifdef NDEBUG
133134
#define ESP_ERROR_CHECK_WITHOUT_ABORT(x) ({ \
134-
esp_err_t __err_rc = (x); \
135-
__err_rc; \
135+
esp_err_t err_rc_ = (x); \
136+
err_rc_; \
136137
})
137138
#else
138139
#define ESP_ERROR_CHECK_WITHOUT_ABORT(x) ({ \
139-
esp_err_t __err_rc = (x); \
140-
if (__err_rc != ESP_OK) { \
141-
_esp_error_check_failed_without_abort(__err_rc, __FILE__, __LINE__, \
142-
__ASSERT_FUNC, #x); \
140+
esp_err_t err_rc_ = (x); \
141+
if (unlikely(err_rc_ != ESP_OK)) { \
142+
_esp_error_check_failed_without_abort(err_rc_, __FILE__, __LINE__, \
143+
__ASSERT_FUNC, #x); \
143144
} \
144-
__err_rc; \
145+
err_rc_; \
145146
})
146147
#endif //NDEBUG
147148

docs/doxygen/Doxyfile_common

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,8 @@ INPUT = \
289289
$(IDF_PATH)/components/esp_ringbuf/include/freertos/ringbuf.h \
290290
### Helper functions for error codes
291291
$(IDF_PATH)/components/esp_common/include/esp_err.h \
292+
### Check macros
293+
$(IDF_PATH)/components/esp_common/include/esp_check.h \
292294
### System APIs
293295
$(IDF_PATH)/components/esp_system/include/esp_system.h \
294296
### Modbus controller component header file

docs/en/api-guides/error-handling.rst

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,71 @@ Error message will typically look like this::
6868

6969
- 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.
7070

71+
.. _esp-error-check-without-abort-macro:
72+
73+
``ESP_ERROR_CHECK_WITHOUT_ABORT`` macro
74+
---------------------------------------
75+
76+
:cpp:func:`ESP_ERROR_CHECK_WITHOUT_ABORT` macro serves similar purpose as ``ESP_ERROR_CHECK``, except that it won't call ``abort()``.
77+
78+
.. _esp-return-on-error-macro:
79+
80+
``ESP_RETURN_ON_ERROR`` macro
81+
-----------------------------
82+
83+
: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.
84+
85+
.. _esp-goto-on-error-macro:
86+
87+
``ESP_GOTO_ON_ERROR`` macro
88+
---------------------------
89+
90+
: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`.
91+
92+
.. _esp-return-on-false-macro:
93+
94+
``ESP_RETURN_ON_FALSE`` macro
95+
-----------------------------
96+
97+
: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`.
98+
99+
.. _esp-goto-on-false-macro:
100+
101+
``ESP_GOTO_ON_FALSE`` macro
102+
---------------------------
103+
104+
: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`.
105+
106+
.. _check_macros_examples:
107+
108+
``CHECK MACROS Examples``
109+
-------------------------
110+
111+
Some examples::
112+
113+
static const char* TAG = "Test";
114+
115+
esp_err_t test_func(void)
116+
{
117+
esp_err_t ret = ESP_OK;
118+
119+
ESP_ERROR_CHECK(x); // err message printed if `x` is not `ESP_OK`, and then `abort()`.
120+
ESP_ERROR_CHECK_WITHOUT_ABORT(x); // err message printed if `x` is not `ESP_OK`, without `abort()`.
121+
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`.
122+
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`.
123+
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`.
124+
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`.
125+
126+
err:
127+
// clean up
128+
return ret;
129+
}
130+
131+
.. note::
132+
133+
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.
134+
135+
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.
71136

72137
Error handling patterns
73138
-----------------------

0 commit comments

Comments
 (0)