1 /* 2 * Copyright (c) 2022 - 2024, Nordic Semiconductor ASA 3 * All rights reserved. 4 * 5 * SPDX-License-Identifier: BSD-3-Clause 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright notice, this 11 * list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the copyright holder nor the names of its 18 * contributors may be used to endorse or promote products derived from this 19 * software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #ifndef NRFX_UTILS_H__ 35 #define NRFX_UTILS_H__ 36 37 #include "nrfx_utils_internal.h" 38 39 /** 40 * @defgroup nrfx_utils Preprocessor utility macros 41 * @{ 42 * @ingroup nrfx 43 * @brief Preprocessor utility macros. 44 */ 45 46 /** 47 * @brief Macro for inserting code depending on whether @p _flag exists and expands to 1 or not. 48 * 49 * To prevent the preprocessor from treating commas as argument 50 * separators, the @p _if_1_code and @p _else_code expressions must be 51 * inside brackets/parentheses: <tt>()</tt>. These are stripped away 52 * during macro expansion. 53 * 54 * Example: 55 * 56 * NRFX_COND_CODE_1(CONFIG_FLAG, (uint32_t x;), (there_is_no_flag();)) 57 * 58 * If @p CONFIG_FLAG is defined to 1, this expands to: 59 * 60 * uint32_t x; 61 * 62 * It expands to <tt>there_is_no_flag();</tt> otherwise. 63 * 64 * This could be used as an alternative to: 65 * 66 * #if defined(CONFIG_FLAG) && (CONFIG_FLAG == 1) 67 * #define MAYBE_DECLARE(x) uint32_t x 68 * #else 69 * #define MAYBE_DECLARE(x) there_is_no_flag() 70 * #endif 71 * 72 * MAYBE_DECLARE(x); 73 * 74 * However, the advantage of COND_CODE_1() is that code is resolved in 75 * place where it is used, while the @p \#if method defines @p 76 * MAYBE_DECLARE on two lines and requires it to be invoked again on a 77 * separate line. This makes COND_CODE_1() more concise and also 78 * sometimes more useful when used within another macro's expansion. 79 * 80 * @note @p _flag can be the result of preprocessor expansion, 81 * however @p _if_1_code is only expanded if @p _flag expands 82 * to the integer literal 1. Integer expressions that evaluate 83 * to 1, e.g. after doing some arithmetic, will not work. 84 * 85 * @param[in] _flag Evaluated flag 86 * @param[in] _if_1_code Result if @p _flag expands to 1; must be in parentheses 87 * @param[in] _else_code Result otherwise; must be in parentheses 88 */ 89 #define NRFX_COND_CODE_1(_flag, _if_1_code, _else_code) \ 90 _NRFX_COND_CODE_1(_flag, _if_1_code, _else_code) 91 92 /** 93 * @brief Macro for inserting code depending on whether @p _flag exists and expands to 0 or not. 94 * 95 * This is like @ref NRFX_COND_CODE_1(), except that it tests whether @p _flag 96 * expands to the integer literal 0. It expands to @p _if_0_code if 97 * so, and @p _else_code otherwise; both of these must be enclosed in 98 * parentheses. 99 * 100 * @param[in] _flag Evaluated flag 101 * @param[in] _if_0_code Result if @p _flag expands to 0; must be in parentheses 102 * @param[in] _else_code Result otherwise; must be in parentheses 103 */ 104 #define NRFX_COND_CODE_0(_flag, _if_0_code, _else_code) \ 105 _NRFX_COND_CODE_0(_flag, _if_0_code, _else_code) 106 107 /** 108 * @brief Macro for checking for macro definition in compiler-visible expressions 109 * 110 * It has the effect of taking a macro value that may be defined to "1" 111 * or may not be defined at all and turning it into a literal 112 * expression that can be handled by the C compiler instead of just 113 * the preprocessor. 114 * 115 * That is, it works similarly to <tt>\#if defined(CONFIG_FOO)</tt> 116 * except that its expansion is a C expression. Thus, much <tt>\#ifdef</tt> 117 * usage can be replaced with equivalents like: 118 * 119 * if (IS_ENABLED(CONFIG_FOO)) { 120 * do_something_with_foo 121 * } 122 * 123 * This is cleaner since the compiler can generate errors and warnings 124 * for @p do_something_with_foo even when @p CONFIG_FOO is undefined. 125 * 126 * @param[in] config_macro Macro to check 127 * 128 * @return 1 if @p config_macro is defined to 1, 0 otherwise (including 129 * if @p config_macro is not defined) 130 */ 131 #define NRFX_IS_ENABLED(config_macro) _NRFX_IS_ENABLED1(config_macro) 132 133 /** 134 * @brief Macro for generating a sequence of code with configurable separator. 135 * 136 * Example: 137 * 138 * #define FOO(i, _) MY_PWM ## i 139 * { NRFX_LISTIFY(PWM_COUNT, FOO, (,)) } 140 * 141 * The above two lines expand to: 142 * 143 * { MY_PWM0 , MY_PWM1 } 144 * 145 * @param[in] LEN The length of the sequence. Must be an integer literal less 146 * than 255. 147 * @param[in] F A macro function that accepts at least two arguments: 148 * <tt>F(i, ...)</tt>. @p F is called repeatedly in the expansion. 149 * Its first argument @p i is the index in the sequence, and 150 * the variable list of arguments passed to LISTIFY are passed 151 * through to @p F. 152 * @param[in] sep Separator (e.g. comma or semicolon). Must be in parentheses; 153 * this is required to enable providing a comma as separator. 154 * 155 * @note Calling NRFX_LISTIFY with undefined arguments has undefined behavior. 156 */ 157 #define NRFX_LISTIFY(LEN, F, sep, ...) \ 158 NRFX_CONCAT_2(_NRFX_LISTIFY_, LEN)(F, sep, __VA_ARGS__) 159 160 /** 161 * @brief Macro for checking if input argument is empty. 162 * 163 * Empty means that nothing is provided or provided value is resolved to nothing 164 * (e.g. empty define). 165 * 166 * Macro idea is taken from P99 which is under Apache 2.0 license and described by 167 * Jens Gustedt https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/ 168 * 169 * @param arg Argument. 170 * 171 * @retval 1 if argument is empty. 172 * @retval 0 if argument is not empty. 173 */ 174 #define NRFX_IS_EMPTY(arg) _NRFX_IS_EMPTY(arg) 175 176 /** 177 * @brief Macro for calculating number of arguments in the variable arguments list minus one. 178 * 179 * @param[in] ... List of arguments 180 * 181 * @return Number of variadic arguments in the argument list, minus one 182 */ 183 #define NRFX_NUM_VA_ARGS_LESS_1(...) \ 184 _NRFX_NUM_VA_ARGS_LESS_1_IMPL(__VA_ARGS__, 63, 62, 61, \ 185 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, \ 186 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, \ 187 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, \ 188 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, \ 189 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, \ 190 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, ~) 191 192 /** 193 * @brief Macro for concatenating multiple arguments. 194 * 195 * Support up to 8 arguments. 196 * 197 * @param[in] ... Arguments to concatenate. 198 */ 199 #define NRFX_CONCAT(...) \ 200 NRFX_CONCAT_2(_NRFX_CONCAT_, NRFX_NUM_VA_ARGS_LESS_1(__VA_ARGS__))(__VA_ARGS__) 201 202 /** 203 * @brief Macro for checking if argument starts with opening round bracket and contains matching 204 * closing bracket (parenthesis). 205 * 206 * @param[in] x Input argument. 207 * 208 * @retval 1 If input argument starts with opening bracket and contains closing bracket. 209 * @retval 0 If input argument does not match above mentioned condition. 210 */ 211 #define NRFX_ARG_HAS_PARENTHESIS(x) _NRFX_GET_ARG3(_NRFX_EVAL(_NRFX_ARG_HAS_PARENTHESIS x, 1, 0)) 212 213 /** 214 * @brief Macro for calling a macro @p F on each provided argument with a given 215 * separator between each call. 216 * 217 * Example: 218 * 219 * #define F(x) int a##x 220 * NRFX_FOR_EACH(F, (;), 4, 5, 6); 221 * 222 * This expands to: 223 * 224 * int a4; 225 * int a5; 226 * int a6; 227 * 228 * @param F Macro to invoke 229 * @param sep Separator (e.g. comma or semicolon). Must be in parentheses; 230 * this is required to enable providing a comma as a separator. 231 * @param ... Variable argument list. The macro @p F is invoked as 232 * <tt>F(element)</tt> for each element in the list. 233 */ 234 #define NRFX_FOR_EACH(F, sep, ...) \ 235 _NRFX_FOR_EACH(F, sep, NRFX_REVERSE_ARGS(__VA_ARGS__)) 236 237 /** 238 * @brief Call macro @p F on each provided argument, with the argument's index 239 * as an additional parameter. 240 * 241 * This is like @ref NRFX_FOR_EACH(), except @p F should be a macro which takes two 242 * arguments: <tt>F(index, variable_arg)</tt>. 243 * 244 * Example: 245 * 246 * #define F(idx, x) int a##idx = x 247 * NRFX_FOR_EACH_IDX(F, (;), 4, 5, 6); 248 * 249 * This expands to: 250 * 251 * int a0 = 4; 252 * int a1 = 5; 253 * int a2 = 6; 254 * 255 * @param F Macro to invoke 256 * @param sep Separator (e.g. comma or semicolon). Must be in parentheses; 257 * this is required to enable providing a comma as a separator. 258 * @param ... Variable argument list. The macro @p F is invoked as 259 * <tt>F(index, element)</tt> for each element in the list. 260 */ 261 #define NRFX_FOR_EACH_IDX(F, sep, ...) \ 262 _NRFX_FOR_EACH_IDX(F, sep, NRFX_REVERSE_ARGS(__VA_ARGS__)) 263 264 /** 265 * @brief Macro for calling macro @p F on each provided argument, with an additional fixed 266 * argument as a parameter. 267 * 268 * This is like @ref NRFX_FOR_EACH(), except @p F should be a macro which takes two 269 * arguments: <tt>F(variable_arg, fixed_arg)</tt>. 270 * 271 * Example: 272 * 273 * static void func(int val, void *dev); 274 * NRFX_FOR_EACH_FIXED_ARG(func, (;), dev, 4, 5, 6); 275 * 276 * This expands to: 277 * 278 * func(4, dev); 279 * func(5, dev); 280 * func(6, dev); 281 * 282 * @param F Macro to invoke 283 * @param sep Separator (e.g. comma or semicolon). Must be in parentheses; 284 * this is required to enable providing a comma as a separator. 285 * @param fixed_arg Fixed argument passed to @p F as the second macro parameter. 286 * @param ... Variable argument list. The macro @p F is invoked as 287 * <tt>F(element, fixed_arg)</tt> for each element in the list. 288 */ 289 #define NRFX_FOR_EACH_FIXED_ARG(F, sep, fixed_arg, ...) \ 290 _NRFX_FOR_EACH_FIXED_ARG(F, sep, fixed_arg, NRFX_REVERSE_ARGS(__VA_ARGS__)) 291 292 /** 293 * @brief Macro from calling macro @p F for each variable argument with an index and fixed 294 * argument 295 * 296 * This is like the combination of @ref NRFX_FOR_EACH_IDX() with @ref NRFX_FOR_EACH_FIXED_ARG(). 297 * 298 * Example: 299 * 300 * #define F(idx, x, fixed_arg) int fixed_arg##idx = x 301 * NRFX_FOR_EACH_IDX_FIXED_ARG(F, (;), a, 4, 5, 6); 302 * 303 * This expands to: 304 * 305 * int a0 = 4; 306 * int a1 = 5; 307 * int a2 = 6; 308 * 309 * @param F Macro to invoke 310 * @param sep Separator (e.g. comma or semicolon). Must be in parentheses; 311 * This is required to enable providing a comma as a separator. 312 * @param fixed_arg Fixed argument passed to @p F as the third macro parameter. 313 * @param ... Variable list of arguments. The macro @p F is invoked as 314 * <tt>F(index, element, fixed_arg)</tt> for each element in 315 * the list. 316 */ 317 #define NRFX_FOR_EACH_IDX_FIXED_ARG(F, sep, fixed_arg, ...) \ 318 _NRFX_FOR_EACH_IDX_FIXED_ARG(F, sep, fixed_arg, NRFX_REVERSE_ARGS(__VA_ARGS__)) 319 320 /** 321 * @brief Macro for reversing arguments order. 322 * 323 * @param ... Variable argument list. 324 * 325 * @return Input arguments in reversed order. 326 */ 327 #define NRFX_REVERSE_ARGS(...) \ 328 _NRFX_FOR_EACH_ENGINE(_NRFX_FOR_EACH_EXEC, (,), NRFX_EVAL, _, __VA_ARGS__) 329 330 331 /** 332 * @brief Macro for getting the highest value from input arguments. 333 * 334 * It is similar to @ref NRFX_MAX but accepts a variable number of arguments. 335 * 336 * @note Input arguments must be numeric variables. 337 * 338 * @param ... Variable argument list. 339 * 340 * @return Highest value from the input list. 341 */ 342 #define NRFX_MAX_N(...) \ 343 NRFX_EVAL(NRFX_FOR_EACH(_NRFX_MAX_P1, (), __VA_ARGS__) 0 \ 344 NRFX_FOR_EACH(_NRFX_MAX_P2, (), __VA_ARGS__)) 345 346 /** @} */ 347 348 #endif /* NRFX_UTILS_H__ */ 349