/* * Copyright (c) 2022 - 2025, Nordic Semiconductor ASA * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef NRFX_UTILS_H__ #define NRFX_UTILS_H__ #include "nrfx_utils_internal.h" /** * @defgroup nrfx_utils Preprocessor utility macros * @{ * @ingroup nrfx * @brief Preprocessor utility macros. */ /** * @brief Macro for inserting code depending on whether @p _flag exists and expands to 1 or not. * * To prevent the preprocessor from treating commas as argument * separators, the @p _if_1_code and @p _else_code expressions must be * inside brackets/parentheses: (). These are stripped away * during macro expansion. * * Example: * * NRFX_COND_CODE_1(CONFIG_FLAG, (uint32_t x;), (there_is_no_flag();)) * * If @p CONFIG_FLAG is defined to 1, this expands to: * * uint32_t x; * * It expands to there_is_no_flag(); otherwise. * * This could be used as an alternative to: * * #if defined(CONFIG_FLAG) && (CONFIG_FLAG == 1) * #define MAYBE_DECLARE(x) uint32_t x * #else * #define MAYBE_DECLARE(x) there_is_no_flag() * #endif * * MAYBE_DECLARE(x); * * However, the advantage of COND_CODE_1() is that code is resolved in * place where it is used, while the @p \#if method defines @p * MAYBE_DECLARE on two lines and requires it to be invoked again on a * separate line. This makes COND_CODE_1() more concise and also * sometimes more useful when used within another macro's expansion. * * @note @p _flag can be the result of preprocessor expansion, * however @p _if_1_code is only expanded if @p _flag expands * to the integer literal 1. Integer expressions that evaluate * to 1, e.g. after doing some arithmetic, will not work. * * @param[in] _flag Evaluated flag * @param[in] _if_1_code Result if @p _flag expands to 1; must be in parentheses * @param[in] _else_code Result otherwise; must be in parentheses */ #define NRFX_COND_CODE_1(_flag, _if_1_code, _else_code) \ _NRFX_COND_CODE_1(_flag, _if_1_code, _else_code) /** * @brief Macro for inserting code depending on whether @p _flag exists and expands to 0 or not. * * This is like @ref NRFX_COND_CODE_1(), except that it tests whether @p _flag * expands to the integer literal 0. It expands to @p _if_0_code if * so, and @p _else_code otherwise; both of these must be enclosed in * parentheses. * * @param[in] _flag Evaluated flag * @param[in] _if_0_code Result if @p _flag expands to 0; must be in parentheses * @param[in] _else_code Result otherwise; must be in parentheses */ #define NRFX_COND_CODE_0(_flag, _if_0_code, _else_code) \ _NRFX_COND_CODE_0(_flag, _if_0_code, _else_code) /** * @brief Macro for checking for macro definition in compiler-visible expressions * * It has the effect of taking a macro value that may be defined to "1" * or may not be defined at all and turning it into a literal * expression that can be handled by the C compiler instead of just * the preprocessor. * * That is, it works similarly to \#if defined(CONFIG_FOO) * except that its expansion is a C expression. Thus, much \#ifdef * usage can be replaced with equivalents like: * * if (IS_ENABLED(CONFIG_FOO)) { * do_something_with_foo * } * * This is cleaner since the compiler can generate errors and warnings * for @p do_something_with_foo even when @p CONFIG_FOO is undefined. * * @param[in] config_macro Macro to check * * @return 1 if @p config_macro is defined to 1, 0 otherwise (including * if @p config_macro is not defined) */ #define NRFX_IS_ENABLED(config_macro) _NRFX_IS_ENABLED1(config_macro) /** * @brief Macro for generating a sequence of code with configurable separator. * * Example: * * #define FOO(i, _) MY_PWM ## i * { NRFX_LISTIFY(PWM_COUNT, FOO, (,)) } * * The above two lines expand to: * * { MY_PWM0 , MY_PWM1 } * * @param[in] LEN The length of the sequence. Must be an integer literal less * than 255. * @param[in] F A macro function that accepts at least two arguments: * F(i, ...). @p F is called repeatedly in the expansion. * Its first argument @p i is the index in the sequence, and * the variable list of arguments passed to LISTIFY are passed * through to @p F. * @param[in] sep Separator (e.g. comma or semicolon). Must be in parentheses; * this is required to enable providing a comma as separator. * * @note Calling NRFX_LISTIFY with undefined arguments has undefined behavior. */ #define NRFX_LISTIFY(LEN, F, sep, ...) \ NRFX_CONCAT_2(_NRFX_LISTIFY_, LEN)(F, sep, __VA_ARGS__) /** * @brief Macro for checking if input argument is empty. * * Empty means that nothing is provided or provided value is resolved to nothing * (e.g. empty define). * * Macro idea is taken from P99 which is under Apache 2.0 license and described by * Jens Gustedt https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/ * * @param arg Argument. * * @retval 1 if argument is empty. * @retval 0 if argument is not empty. */ #define NRFX_IS_EMPTY(arg) _NRFX_IS_EMPTY(arg) /** * @brief Macro for calculating number of arguments in the variable arguments list minus one. * * @param[in] ... List of arguments * * @return Number of variadic arguments in the argument list, minus one */ #define NRFX_NUM_VA_ARGS_LESS_1(...) \ _NRFX_NUM_VA_ARGS_LESS_1_IMPL(__VA_ARGS__, 63, 62, 61, \ 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, \ 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, \ 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, \ 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, \ 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, \ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, ~) /** * @brief Macro for concatenating multiple arguments. * * Support up to 8 arguments. * * @param[in] ... Arguments to concatenate. */ #define NRFX_CONCAT(...) \ NRFX_CONCAT_2(_NRFX_CONCAT_, NRFX_NUM_VA_ARGS_LESS_1(__VA_ARGS__))(__VA_ARGS__) /** * @brief Macro for checking if argument starts with opening round bracket and contains matching * closing bracket (parenthesis). * * @param[in] x Input argument. * * @retval 1 If input argument starts with opening bracket and contains closing bracket. * @retval 0 If input argument does not match above mentioned condition. */ #define NRFX_ARG_HAS_PARENTHESIS(x) _NRFX_GET_ARG3(_NRFX_EVAL(_NRFX_ARG_HAS_PARENTHESIS x, 1, 0)) /** * @brief Macro for calling a macro @p F on each provided argument with a given * separator between each call. * * Example: * * #define F(x) int a##x * NRFX_FOR_EACH(F, (;), 4, 5, 6); * * This expands to: * * int a4; * int a5; * int a6; * * @param F Macro to invoke * @param sep Separator (e.g. comma or semicolon). Must be in parentheses; * this is required to enable providing a comma as a separator. * @param ... Variable argument list. The macro @p F is invoked as * F(element) for each element in the list. */ #define NRFX_FOR_EACH(F, sep, ...) \ _NRFX_FOR_EACH(F, sep, NRFX_REVERSE_ARGS(__VA_ARGS__)) /** * @brief Call macro @p F on each provided argument, with the argument's index * as an additional parameter. * * This is like @ref NRFX_FOR_EACH(), except @p F should be a macro which takes two * arguments: F(index, variable_arg). * * Example: * * #define F(idx, x) int a##idx = x * NRFX_FOR_EACH_IDX(F, (;), 4, 5, 6); * * This expands to: * * int a0 = 4; * int a1 = 5; * int a2 = 6; * * @param F Macro to invoke * @param sep Separator (e.g. comma or semicolon). Must be in parentheses; * this is required to enable providing a comma as a separator. * @param ... Variable argument list. The macro @p F is invoked as * F(index, element) for each element in the list. */ #define NRFX_FOR_EACH_IDX(F, sep, ...) \ _NRFX_FOR_EACH_IDX(F, sep, NRFX_REVERSE_ARGS(__VA_ARGS__)) /** * @brief Macro for calling macro @p F on each provided argument, with an additional fixed * argument as a parameter. * * This is like @ref NRFX_FOR_EACH(), except @p F should be a macro which takes two * arguments: F(variable_arg, fixed_arg). * * Example: * * static void func(int val, void *dev); * NRFX_FOR_EACH_FIXED_ARG(func, (;), dev, 4, 5, 6); * * This expands to: * * func(4, dev); * func(5, dev); * func(6, dev); * * @param F Macro to invoke * @param sep Separator (e.g. comma or semicolon). Must be in parentheses; * this is required to enable providing a comma as a separator. * @param fixed_arg Fixed argument passed to @p F as the second macro parameter. * @param ... Variable argument list. The macro @p F is invoked as * F(element, fixed_arg) for each element in the list. */ #define NRFX_FOR_EACH_FIXED_ARG(F, sep, fixed_arg, ...) \ _NRFX_FOR_EACH_FIXED_ARG(F, sep, fixed_arg, NRFX_REVERSE_ARGS(__VA_ARGS__)) /** * @brief Macro from calling macro @p F for each variable argument with an index and fixed * argument * * This is like the combination of @ref NRFX_FOR_EACH_IDX() with @ref NRFX_FOR_EACH_FIXED_ARG(). * * Example: * * #define F(idx, x, fixed_arg) int fixed_arg##idx = x * NRFX_FOR_EACH_IDX_FIXED_ARG(F, (;), a, 4, 5, 6); * * This expands to: * * int a0 = 4; * int a1 = 5; * int a2 = 6; * * @param F Macro to invoke * @param sep Separator (e.g. comma or semicolon). Must be in parentheses; * This is required to enable providing a comma as a separator. * @param fixed_arg Fixed argument passed to @p F as the third macro parameter. * @param ... Variable list of arguments. The macro @p F is invoked as * F(index, element, fixed_arg) for each element in * the list. */ #define NRFX_FOR_EACH_IDX_FIXED_ARG(F, sep, fixed_arg, ...) \ _NRFX_FOR_EACH_IDX_FIXED_ARG(F, sep, fixed_arg, NRFX_REVERSE_ARGS(__VA_ARGS__)) /** * @brief Macro for reversing arguments order. * * @param ... Variable argument list. * * @return Input arguments in reversed order. */ #define NRFX_REVERSE_ARGS(...) \ _NRFX_FOR_EACH_ENGINE(_NRFX_FOR_EACH_EXEC, (,), NRFX_EVAL, _, __VA_ARGS__) /** * @brief Macro for getting the highest value from input arguments. * * It is similar to @ref NRFX_MAX but accepts a variable number of arguments. * * @note Input arguments must be numeric variables. * * @param ... Variable argument list. * * @return Highest value from the input list. */ #define NRFX_MAX_N(...) \ NRFX_EVAL(NRFX_FOR_EACH(_NRFX_MAX_P1, (), __VA_ARGS__) 0 \ NRFX_FOR_EACH(_NRFX_MAX_P2, (), __VA_ARGS__)) /** @} */ #endif /* NRFX_UTILS_H__ */