|
| 1 | +/* |
| 2 | + * Copyright (c) 2024 Nordic Semiconductor ASA |
| 3 | + * |
| 4 | + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause |
| 5 | + */ |
| 6 | + |
| 7 | +#ifndef _APP_COMMON_H_ |
| 8 | +#define _APP_COMMON_H_ |
| 9 | + |
| 10 | +#include <zephyr/kernel.h> |
| 11 | +#include <zephyr/logging/log_ctrl.h> |
| 12 | +#include <zephyr/sys/util.h> /* For Zephyr's utility macros, including MAX */ |
| 13 | +#if defined(CONFIG_MEMFAULT) |
| 14 | +#include <memfault/panics/assert.h> |
| 15 | +#endif |
| 16 | + |
| 17 | +#ifdef __cplusplus |
| 18 | +extern "C" { |
| 19 | +#endif |
| 20 | + |
| 21 | +/** @brief Handle fatal error. |
| 22 | + * @param is_watchdog_timeout Boolean indicating if the macro was called upon a watchdog timeout. |
| 23 | + */ |
| 24 | +#define FATAL_ERROR_HANDLE(is_watchdog_timeout) \ |
| 25 | + do { \ |
| 26 | + LOG_PANIC(); \ |
| 27 | + if (is_watchdog_timeout) { \ |
| 28 | + IF_ENABLED(CONFIG_MEMFAULT, (MEMFAULT_SOFTWARE_WATCHDOG())); \ |
| 29 | + } \ |
| 30 | + k_sleep(K_SECONDS(10)); \ |
| 31 | + __ASSERT(false, "SEND_FATAL_ERROR() macro called"); \ |
| 32 | + } while (0) |
| 33 | + |
| 34 | +/** @brief Macro used to handle fatal errors. */ |
| 35 | +#define SEND_FATAL_ERROR() FATAL_ERROR_HANDLE(0) |
| 36 | + |
| 37 | +/** @brief Macro used to handle watchdog timeouts. */ |
| 38 | +#define SEND_FATAL_ERROR_WATCHDOG_TIMEOUT() FATAL_ERROR_HANDLE(1) |
| 39 | + |
| 40 | +/* Helper macros for computing MAX with different numbers of arguments */ |
| 41 | +#define MAX_1(a1) (a1) |
| 42 | +#define MAX_2(a1, a2) MAX(a1, a2) |
| 43 | +#define MAX_3(a1, a2, a3) MAX(MAX_2(a1, a2), a3) |
| 44 | +#define MAX_4(a1, a2, a3, a4) MAX(MAX_3(a1, a2, a3), a4) |
| 45 | +#define MAX_5(a1, a2, a3, a4, a5) MAX(MAX_4(a1, a2, a3, a4), a5) |
| 46 | +#define MAX_6(a1, a2, a3, a4, a5, a6) MAX(MAX_5(a1, a2, a3, a4, a5), a6) |
| 47 | +#define MAX_7(a1, a2, a3, a4, a5, a6, a7) MAX(MAX_6(a1, a2, a3, a4, a5, a6), a7) |
| 48 | +#define MAX_8(a1, a2, a3, a4, a5, a6, a7, a8) MAX(MAX_7(a1, a2, a3, a4, a5, a6, a7), a8) |
| 49 | +#define MAX_9(a1, a2, a3, a4, a5, a6, a7, a8, a9) MAX(MAX_8(a1, a2, a3, a4, a5, a6, a7, a8), a9) |
| 50 | +#define MAX_10(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) \ |
| 51 | + MAX(MAX_9(a1, a2, a3, a4, a5, a6, a7, a8, a9), a10) |
| 52 | + |
| 53 | +#define SELECT_MAX_N(N) CONCAT(MAX_, N) |
| 54 | + |
| 55 | +/** |
| 56 | + * @brief Macro to compute the maximum of a list of numbers. |
| 57 | + * |
| 58 | + * @param ... List of numbers to compute the maximum of. |
| 59 | + */ |
| 60 | +#define MAX_N(...) SELECT_MAX_N(NUM_VA_ARGS(__VA_ARGS__))(__VA_ARGS__) |
| 61 | + |
| 62 | +/** |
| 63 | + * @brief Helper macro for computing the size of a type. |
| 64 | + * The intended use is with X macros to generate a list of sizes for each type in a list of types. |
| 65 | + * |
| 66 | + * @param _chan Channel to compute the size of the type for. |
| 67 | + * @param _type Type to compute the size of. |
| 68 | + * |
| 69 | + * @return Size of the type. |
| 70 | + */ |
| 71 | +#define SIZE_OF_TYPE(_chan, _type) sizeof(_type), |
| 72 | + |
| 73 | +/** |
| 74 | + * @brief Macro to compute the maximum message size from a list of channel date types. |
| 75 | + * The macro expands to a list of sizeof(type) for each channel's type, followed by a 0 to |
| 76 | + * account for the trailing comma when expanding SIZE_OF_TYPE |
| 77 | + * The MAX_N macro is used to find the maximum value in the list. |
| 78 | + * Example: MAX_N(sizeof(struct cloud_msg), sizeof(enum fota_msg_type), 0) |
| 79 | +
|
| 80 | + * @param _CHAN_LIST List of channels to compute the maximum message size from. |
| 81 | + * The list should be in the format: (CHANNEL_NAME, type) |
| 82 | + * |
| 83 | + * @return Maximum message size from the list of channels |
| 84 | + */ |
| 85 | +#define MAX_MSG_SIZE_FROM_LIST(_CHAN_LIST) MAX_N(_CHAN_LIST(SIZE_OF_TYPE) 0) |
| 86 | + |
| 87 | +#ifdef __cplusplus |
| 88 | +} |
| 89 | +#endif |
| 90 | + |
| 91 | +#endif /* _APP_COMMON_H_ */ |
0 commit comments