firmware-base/src/macros.h
2025-05-23 08:56:55 +02:00

391 lines
14 KiB
C++

#ifndef MACROS_H
#define MACROS_H
#include "./xtypes.h"
// Macros for adding
#define INC_0 1
#define INC_1 2
#define INC_2 3
#define INC_3 4
#define INC_4 5
#define INC_5 6
#define INC_6 7
#define INC_7 8
#define INC_8 9
#define INCREMENT_(n) INC_##n
#define INCREMENT(n) INCREMENT_(n)
// Macros for subtracting
#define DEC_1 0
#define DEC_2 1
#define DEC_3 2
#define DEC_4 3
#define DEC_5 4
#define DEC_6 5
#define DEC_7 6
#define DEC_8 7
#define DEC_9 8
#define DECREMENT_(n) DEC_##n
#define DECREMENT(n) DECREMENT_(n)
// compiler - & C quirks
#ifndef FORCE_INLINE
#define FORCE_INLINE __attribute__((always_inline)) inline
#endif
#define _UNUSED __attribute__((unused))
// fallback noop
#define NOOP (void(0))
// Option testing
// Use NUM_ARGS(__VA_ARGS__) to get the number of variadic arguments
#define _NUM_ARGS(_, n, m, l, k, j, i, h, g, f, e, d, c, b, a, Z, Y, X, W, V, U, T, S, R, Q, P, O, N, M, L, K, J, I, H, G, F, E, D, C, B, A, OUT, ...) OUT
#define NUM_ARGS(V...) _NUM_ARGS(0, V, 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)
// Use TWO_ARGS(__VA_ARGS__) to get whether there are 1, 2, or >2 arguments
#define _TWO_ARGS(_, n, m, l, k, j, i, h, g, f, e, d, c, b, a, Z, Y, X, W, V, U, T, S, R, Q, P, O, N, M, L, K, J, I, H, G, F, E, D, C, B, A, OUT, ...) OUT
#define TWO_ARGS(V...) _TWO_ARGS(0, V, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0)
// Concatenate symbol names, without or with pre-expansion
#define _CAT(a, V...) a##V
#define CAT(a, V...) _CAT(a, V)
// Macros to chain up to 40 conditions
#define _DO_1(W, C, A) (_##W##_1(A))
#define _DO_2(W, C, A, B) (_##W##_1(A) C _##W##_1(B))
#define _DO_3(W, C, A, V...) (_##W##_1(A) C _DO_2(W, C, V))
#define _DO_4(W, C, A, V...) (_##W##_1(A) C _DO_3(W, C, V))
#define _DO_5(W, C, A, V...) (_##W##_1(A) C _DO_4(W, C, V))
#define _DO_6(W, C, A, V...) (_##W##_1(A) C _DO_5(W, C, V))
#define _DO_7(W, C, A, V...) (_##W##_1(A) C _DO_6(W, C, V))
#define _DO_8(W, C, A, V...) (_##W##_1(A) C _DO_7(W, C, V))
#define _DO_9(W, C, A, V...) (_##W##_1(A) C _DO_8(W, C, V))
#define _DO_10(W, C, A, V...) (_##W##_1(A) C _DO_9(W, C, V))
#define _DO_11(W, C, A, V...) (_##W##_1(A) C _DO_10(W, C, V))
#define _DO_12(W, C, A, V...) (_##W##_1(A) C _DO_11(W, C, V))
#define _DO_13(W, C, A, V...) (_##W##_1(A) C _DO_12(W, C, V))
#define _DO_14(W, C, A, V...) (_##W##_1(A) C _DO_13(W, C, V))
#define _DO_15(W, C, A, V...) (_##W##_1(A) C _DO_14(W, C, V))
#define _DO_16(W, C, A, V...) (_##W##_1(A) C _DO_15(W, C, V))
#define _DO_17(W, C, A, V...) (_##W##_1(A) C _DO_16(W, C, V))
#define _DO_18(W, C, A, V...) (_##W##_1(A) C _DO_17(W, C, V))
#define _DO_19(W, C, A, V...) (_##W##_1(A) C _DO_18(W, C, V))
#define _DO_20(W, C, A, V...) (_##W##_1(A) C _DO_19(W, C, V))
#define _DO_21(W, C, A, V...) (_##W##_1(A) C _DO_20(W, C, V))
#define _DO_22(W, C, A, V...) (_##W##_1(A) C _DO_21(W, C, V))
#define _DO_23(W, C, A, V...) (_##W##_1(A) C _DO_22(W, C, V))
#define _DO_24(W, C, A, V...) (_##W##_1(A) C _DO_23(W, C, V))
#define _DO_25(W, C, A, V...) (_##W##_1(A) C _DO_24(W, C, V))
#define _DO_26(W, C, A, V...) (_##W##_1(A) C _DO_25(W, C, V))
#define _DO_27(W, C, A, V...) (_##W##_1(A) C _DO_26(W, C, V))
#define _DO_28(W, C, A, V...) (_##W##_1(A) C _DO_27(W, C, V))
#define _DO_29(W, C, A, V...) (_##W##_1(A) C _DO_28(W, C, V))
#define _DO_30(W, C, A, V...) (_##W##_1(A) C _DO_29(W, C, V))
#define _DO_31(W, C, A, V...) (_##W##_1(A) C _DO_30(W, C, V))
#define _DO_32(W, C, A, V...) (_##W##_1(A) C _DO_31(W, C, V))
#define _DO_33(W, C, A, V...) (_##W##_1(A) C _DO_32(W, C, V))
#define _DO_34(W, C, A, V...) (_##W##_1(A) C _DO_33(W, C, V))
#define _DO_35(W, C, A, V...) (_##W##_1(A) C _DO_34(W, C, V))
#define _DO_36(W, C, A, V...) (_##W##_1(A) C _DO_35(W, C, V))
#define _DO_37(W, C, A, V...) (_##W##_1(A) C _DO_36(W, C, V))
#define _DO_38(W, C, A, V...) (_##W##_1(A) C _DO_37(W, C, V))
#define _DO_39(W, C, A, V...) (_##W##_1(A) C _DO_38(W, C, V))
#define _DO_40(W, C, A, V...) (_##W##_1(A) C _DO_39(W, C, V))
#define __DO_N(W, C, N, V...) _DO_##N(W, C, V)
#define _DO_N(W, C, N, V...) __DO_N(W, C, N, V)
#define DO(W, C, V...) (_DO_N(W, C, NUM_ARGS(V), V))
#define FIRST(a,...) a
#define SECOND(a,b,...) b
#define THIRD(a,b,c,...) c
#define IS_PROBE(V...) SECOND(V, 0) // Get the second item passed, or 0
#define PROBE() ~, 1 // Second item will be 1 if this is passed
#define _NOT_0 PROBE()
#define NOT(x) IS_PROBE(_CAT(_NOT_, x)) // NOT('0') gets '1'. Anything else gets '0'.
#define _BOOL(x) NOT(NOT(x)) // _BOOL('0') gets '0'. Anything else gets '1'.
#define IF_ELSE(TF) _IF_ELSE(_BOOL(TF))
#define _IF_ELSE(TF) _CAT(_IF_, TF)
#define _IF_1(V...) V _IF_1_ELSE
#define _IF_0(...) _IF_0_ELSE
#define _IF_1_ELSE(...)
#define _IF_0_ELSE(V...) V
// Recognize "true" values: blank, 1, 0x1, true
#define _ISENA_ ~, 1
#define _ISENA_1 ~, 1
#define _ISENA_0x1 ~, 1
#define _ISENA_true ~, 1
#define _ISENA(V...) IS_PROBE(V)
// Macros to evaluate simple option switches
#define _ENA_1(O) _ISENA(CAT(_IS, CAT(ENA_, O)))
#define _DIS_1(O) NOT(_ENA_1(O))
#define ENABLED(V...) DO(ENA, &&, V)
#ifndef MACRO_DISABLED
#define MACRO_DISABLED(V...) DO(DIS, &&, V)
#endif
#define ANY(V...) !MACRO_DISABLED(V)
#define ALL ENABLED
#define NONE MACRO_DISABLED
#define COUNT_ENABLED(V...) DO(ENA, +, V)
#define MANY(V...) (COUNT_ENABLED(V) > 1)
// #define _CAT(a, ...) a ## __VA_ARGS__
// #define SWITCH_ENABLED_ 1
// #define ENABLED(b) _CAT(SWITCH_ENABLED_, b)
// time
#define PENDING(NOW, SOON) ((long)(NOW - (SOON)) < 0)
#define ELAPSED(NOW, SOON) (!PENDING(NOW, SOON))
#define MMM_TO_MMS(MM_M) ((MM_M) / 60.0f)
#define MMS_TO_MMM(MM_S) ((MM_S) * 60.0f)
#define HOUR_MS ((millis_t)1000 * (millis_t)(60 * 60))
#define MIN_MS ((millis_t)1000 * (millis_t)(60))
#define SECS ((millis_t)1000)
// bit masks
#undef __BV
#define __BV(b) (1 << (b))
#define TEST(n, b) !!((n) & __BV(b))
#define SBI(n, b) (n |= __BV(b))
#define CBI(n, b) (n &= ~__BV(b))
#define SET_BIT_TO(N, B, TF) \
do \
{ \
if (TF) \
SBI(N, B); \
else \
CBI(N, B); \
} while (0)
#define _BV32(b) (1UL << (b))
#define TEST32(n, b) !!((n) & _BV32(b))
#define SBI32(n, b) (n |= _BV32(b))
#define CBI32(n, b) (n &= ~_BV32(b))
#define SIGN(a) ((a > 0) - (a < 0))
// math basics
#ifndef WITHIN
#define WITHIN(V, L, H) ((V) >= (L) && (V) <= (H))
#endif
#define NUMERIC(a) WITHIN(a, '0', '9')
#define DECIMAL(a) (NUMERIC(a) || a == '.')
#define NUMERIC_SIGNED(a) (NUMERIC(a) || (a) == '-' || (a) == '+')
#define DECIMAL_SIGNED(a) (DECIMAL(a) || (a) == '-' || (a) == '+')
#define COUNT(a) (sizeof(a) / sizeof(*a))
#ifndef ZERO
#define ZERO(a) memset(a, 0, sizeof(a))
#endif
#define COPY(a, b) memcpy(a, b, MIN(sizeof(a), sizeof(b)))
// #define M_PI 3.14159265358979323846f
#define RADIANS(d) ((d) * M_PI / 180.0f)
#define DEGREES(r) ((r) * 180.0f / M_PI)
#define CEILING(x, y) (((x) + (y) - 1) / (y))
#define UNEAR_ZERO(x) ((x) < 0.000001f)
#define NEAR_ZERO(x) WITHIN(x, -0.000001f, 0.000001f)
#define NEAR(x, y) NEAR_ZERO((x) - (y))
#define RECIPROCAL(x) (NEAR_ZERO(x) ? 0 : (1 / float(x)))
#define FIXFLOAT(f) ({__typeof__(f) _f = (f); _f + (_f < 0 ? -0.0000005f : 0.0000005f); })
// value helper macros
#define ISEOL(C) ((C) == '\n' || (C) == '\r')
#define HEXCHR(a) (NUMERIC(a) ? (a) - '0' : WITHIN(a, 'a', 'f') ? ((a) - 'a' + 10) \
: WITHIN(a, 'A', 'F') ? ((a) - 'A' + 10) \
: -1)
// Macros for initializing arrays
#define ARRAY_6(v1, v2, v3, v4, v5, v6, ...) \
{ \
v1, v2, v3, v4, v5, v6 \
}
#define ARRAY_5(v1, v2, v3, v4, v5, ...) \
{ \
v1, v2, v3, v4, v5 \
}
#define ARRAY_4(v1, v2, v3, v4, ...) \
{ \
v1, v2, v3, v4 \
}
#define ARRAY_3(v1, v2, v3, ...) \
{ \
v1, v2, v3 \
}
#define ARRAY_2(v1, v2, ...) \
{ \
v1, v2 \
}
#define ARRAY_1(v1, ...) \
{ \
v1 \
}
#define _ARRAY_N(N, ...) ARRAY_##N(__VA_ARGS__)
#define ARRAY_N(N, ...) _ARRAY_N(N, __VA_ARGS__)
#define SPACE(A) " " << A << " "
////////////////////////////////////////////////////////////////////////
//
// Macros from Marlin / compat
#ifndef MARLIN_HEX_VERSION
// Clock speed factors
#if !defined(CYCLES_PER_MICROSECOND) && !defined(__STM32F1__)
#define CYCLES_PER_MICROSECOND (F_CPU / 1000000UL) // 16 or 20 on AVR
#endif
// Nanoseconds per cycle
#define NANOSECONDS_PER_CYCLE (1000000000.0 / F_CPU)
// Macros to make a string from a macro
#define STRINGIFY_(M) #M
#define STRINGIFY(M) STRINGIFY_(M)
// Macros to chain up to 40 conditions
#ifdef __cplusplus
#ifndef _MINMAX_H_
#define _MINMAX_H_
extern "C++"
{
// C++11 solution that is standards compliant. Return type is deduced automatically
template <class N>
static constexpr N _MIN(const N val) { return val; }
template <class N>
static constexpr N _MAX(const N val) { return val; }
template <class L, class R>
static constexpr auto _MIN(const L lhs, const R rhs) -> decltype(lhs + rhs)
{
return lhs < rhs ? lhs : rhs;
}
template <class L, class R>
static constexpr auto _MAX(const L lhs, const R rhs) -> decltype(lhs + rhs)
{
return lhs > rhs ? lhs : rhs;
}
template <class T, class... Ts>
static constexpr const T _MIN(T V, Ts... Vs) { return _MIN(V, _MIN(Vs...)); }
template <class T, class... Ts>
static constexpr const T _MAX(T V, Ts... Vs) { return _MAX(V, _MAX(Vs...)); }
}
#endif
// Allow manipulating enumeration value like flags without ugly cast everywhere
#define ENUM_FLAGS(T) \
FORCE_INLINE constexpr T operator&(T x, T y) { return static_cast<T>(static_cast<int>(x) & static_cast<int>(y)); } \
FORCE_INLINE constexpr T operator|(T x, T y) { return static_cast<T>(static_cast<int>(x) | static_cast<int>(y)); } \
FORCE_INLINE constexpr T operator^(T x, T y) { return static_cast<T>(static_cast<int>(x) ^ static_cast<int>(y)); } \
FORCE_INLINE constexpr T operator~(T x) { return static_cast<T>(~static_cast<int>(x)); } \
FORCE_INLINE T &operator&=(T &x, T y) { return x &= y; } \
FORCE_INLINE T &operator|=(T &x, T y) { return x |= y; } \
FORCE_INLINE T &operator^=(T &x, T y) { return x ^= y; }
// C++11 solution that is standard compliant. <type_traits> is not available on all platform
namespace Private
{
template <bool, typename _Tp = void>
struct enable_if
{
};
template <typename _Tp>
struct enable_if<true, _Tp>
{
typedef _Tp type;
};
template <typename T, typename U>
struct is_same
{
enum
{
value = false
};
};
template <typename T>
struct is_same<T, T>
{
enum
{
value = true
};
};
template <typename T, typename... Args>
struct first_type_of
{
typedef T type;
};
template <typename T>
struct first_type_of<T>
{
typedef T type;
};
}
// C++11 solution using SFINAE to detect the existence of a member in a class at compile time.
// It creates a HasMember<Type> structure containing 'value' set to true if the member exists
#define HAS_MEMBER_IMPL(Member) \
namespace Private \
{ \
template <typename Type, typename Yes = char, typename No = long> \
struct HasMember_##Member \
{ \
template <typename C> \
static Yes &test(decltype(&C::Member)); \
template <typename C> \
static No &test(...); \
enum \
{ \
value = sizeof(test<Type>(0)) == sizeof(Yes) \
}; \
}; \
}
// Call the method if it exists, but do nothing if it does not. The method is detected at compile time.
// If the method exists, this is inlined and does not cost anything. Else, an "empty" wrapper is created, returning a default value
#define CALL_IF_EXISTS_IMPL(Return, Method, ...) \
HAS_MEMBER_IMPL(Method) \
namespace Private \
{ \
template <typename T, typename... Args> \
FORCE_INLINE typename enable_if<HasMember_##Method<T>::value, Return>::type Call_##Method(T *t, Args... a) { return static_cast<Return>(t->Method(a...)); } \
_UNUSED static Return Call_##Method(...) { return __VA_ARGS__; } \
}
#define CALL_IF_EXISTS(Return, That, Method, ...) \
static_cast<Return>(Private::Call_##Method(That, ##__VA_ARGS__))
#else
#endif // __cplusplus
#endif // MARLIN_HEX_VERSION
///////////////////////////////////////////////////////
//
// String Conversion / Casting (WString.h substitute)
//
#define CC_STR(s) (const char *)s
#define C_STR(s) (char *)s
#endif // MACROS_H