///////////////////////////////////////////////////////////////////////
// param.h
///////////////////////////////////////////////////////////////////////
#ifndef PARAM_H_
#define PARAM_H_
#include <stdint.h>
#include <stdbool.h>
#include <stdatomic.h>
#include "param_cfg.h"
typedef uint16_t param_id_t;
// Declare all parameter types
// NOTE: _Atomic qualifier on value to make possible atomic access removing the need for explicit locks
//
// with SEGGER IDE when using atomics with locks implement
// SEGGER_RTL_X_atomic_lock()
// SEGGER_RTL_X_atomic_unlock()
// SEGGER_RTL_X_atomic_synchronize()
//
// default implementations in \SEGGER Embedded Studio 8.12a\source\emRun\atomicops.c and \atomic_locking.c
// with header in \SEGGER Embedded Studio 8.12a\include\__SEGGER_RTL.h
//
// with softdevice used we should probably use the softdevice provided enter/exit critical section
//
// if custom locking (not that IRQ gets disabled) is used then param_set/get must not be called from ISR
// otherwise can lead to dead-locks
#define PARAM_INFO_TYPENAME(postfix) param_ ## postfix ## _info_t
#define PARAM_VAL_TYPENAME(postfix) param_ ## postfix ## _val_t
#define PARAM_DECLARE_TYPE(type, postfix) \
typedef struct \
{ \
param_id_t id; \
type def; \
type min; \
type max; \
} PARAM_INFO_TYPENAME(postfix); \
typedef _Atomic type PARAM_VAL_TYPENAME(type, postfix)
PARAM_DECLARE_TYPE(uint8_t, u8);
PARAM_DECLARE_TYPE(int8_t, i8);
PARAM_DECLARE_TYPE(uint16_t, u16);
PARAM_DECLARE_TYPE(int16_t, i16);
PARAM_DECLARE_TYPE(uint32_t, u32);
PARAM_DECLARE_TYPE(int32_t, i32);
PARAM_DECLARE_TYPE(uint64_t, u64);
PARAM_DECLARE_TYPE(int64_t, i64);
PARAM_DECLARE_TYPE(float32_t, f32);
#define PARAM_ENUM(type, name) ePARAM_ ## type ## _ ## name
#define PARAM_U8_ENUM(name) PARAM_ENUM(U8, name)
#define PARAM_I8_ENUM(name) PARAM_ENUM(I8, name)
#define PARAM_U16_ENUM(name) PARAM_ENUM(U16, name)
#define PARAM_I16_ENUM(name) PARAM_ENUM(I16, name)
#define PARAM_U32_ENUM(name) PARAM_ENUM(U32, name)
#define PARAM_I32_ENUM(name) PARAM_ENUM(I32, name)
#define PARAM_U64_ENUM(name) PARAM_ENUM(U64, name)
#define PARAM_I64_ENUM(name) PARAM_ENUM(I64, name)
#define PARAM_F32_ENUM(name) PARAM_ENUM(F32, name)
// Define enum for every parameter type separately, so that we can check when calling set/get
// functions if parameter for the specific type exists by checking if enum for that type exists
//
// u8
typedef enum
{
#define PARAM_U8(name, ...) PARAM_U8_ENUM(name),
#define PARAM_I8(name, ...)
#define PARAM_U16(name, ...)
#define PARAM_I16(name, ...)
#define PARAM_U32(name, ...)
#define PARAM_I32(name, ...)
#define PARAM_U64(name, ...)
#define PARAM_I64(name, ...)
#define PARAM_F32(name, ...)
PARAM_LIST
PARAM_U8_ENUM(NUM_OF)
#undef PARAM_U8
#undef PARAM_I8
#undef PARAM_U16
#undef PARAM_I16
#undef PARAM_U32
#undef PARAM_I32
#undef PARAM_U64
#undef PARAM_I64
#undef PARAM_F32
} param_u8_t;
// i8
typedef enum
{
#define PARAM_U8(name, ...)
#define PARAM_I8(name, ...) PARAM_I8_ENUM(name),
#define PARAM_U16(name, ...)
#define PARAM_I16(name, ...)
#define PARAM_U32(name, ...)
#define PARAM_I32(name, ...)
#define PARAM_U64(name, ...)
#define PARAM_I64(name, ...)
#define PARAM_F32(name, ...)
PARAM_LIST
PARAM_I8_ENUM(NUM_OF)
#undef PARAM_U8
#undef PARAM_I8
#undef PARAM_U16
#undef PARAM_I16
#undef PARAM_U32
#undef PARAM_I32
#undef PARAM_U64
#undef PARAM_I64
#undef PARAM_F32
} param_i8_t;
// u16
typedef enum
{
#define PARAM_U8(name, ...)
#define PARAM_I8(name, ...)
#define PARAM_U16(name, ...) PARAM_U16_ENUM(name),
#define PARAM_I16(name, ...)
#define PARAM_U32(name, ...)
#define PARAM_I32(name, ...)
#define PARAM_U64(name, ...)
#define PARAM_I64(name, ...)
#define PARAM_F32(name, ...)
PARAM_LIST
PARAM_U16_ENUM(NUM_OF)
#undef PARAM_U8
#undef PARAM_I8
#undef PARAM_U16
#undef PARAM_I16
#undef PARAM_U32
#undef PARAM_I32
#undef PARAM_U64
#undef PARAM_I64
#undef PARAM_F32
} param_u16_t;
// i16
typedef enum
{
#define PARAM_U8(name, ...)
#define PARAM_I8(name, ...)
#define PARAM_U16(name, ...)
#define PARAM_I16(name, ...) PARAM_I16_ENUM(name),
#define PARAM_U32(name, ...)
#define PARAM_I32(name, ...)
#define PARAM_U64(name, ...)
#define PARAM_I64(name, ...)
#define PARAM_F32(name, ...)
PARAM_LIST
PARAM_I16_ENUM(NUM_OF)
#undef PARAM_U8
#undef PARAM_I8
#undef PARAM_U16
#undef PARAM_I16
#undef PARAM_U32
#undef PARAM_I32
#undef PARAM_U64
#undef PARAM_I64
#undef PARAM_F32
} param_i16_t;
// u32
typedef enum
{
#define PARAM_U8(name, ...)
#define PARAM_I8(name, ...)
#define PARAM_U16(name, ...)
#define PARAM_I16(name, ...)
#define PARAM_U32(name, ...) PARAM_U32_ENUM(name),
#define PARAM_I32(name, ...)
#define PARAM_U64(name, ...)
#define PARAM_I64(name, ...)
#define PARAM_F32(name, ...)
PARAM_LIST
PARAM_U32_ENUM(NUM_OF)
#undef PARAM_U8
#undef PARAM_I8
#undef PARAM_U16
#undef PARAM_I16
#undef PARAM_U32
#undef PARAM_I32
#undef PARAM_U64
#undef PARAM_I64
#undef PARAM_F32
} param_u32_t;
// i32
typedef enum
{
#define PARAM_U8(name, ...)
#define PARAM_I8(name, ...)
#define PARAM_U16(name, ...)
#define PARAM_I16(name, ...)
#define PARAM_U32(name, ...)
#define PARAM_I32(name, ...) PARAM_I32_ENUM(name),
#define PARAM_U64(name, ...)
#define PARAM_I64(name, ...)
#define PARAM_F32(name, ...)
PARAM_LIST
PARAM_I32_ENUM(NUM_OF)
#undef PARAM_U8
#undef PARAM_I8
#undef PARAM_U16
#undef PARAM_I16
#undef PARAM_U32
#undef PARAM_I32
#undef PARAM_U64
#undef PARAM_I64
#undef PARAM_F32
} param_i32_t;
// u64
typedef enum
{
#define PARAM_U8(name, ...)
#define PARAM_I8(name, ...)
#define PARAM_U16(name, ...)
#define PARAM_I16(name, ...)
#define PARAM_U32(name, ...)
#define PARAM_I32(name, ...)
#define PARAM_U64(name, ...) PARAM_U64_ENUM(name),
#define PARAM_I64(name, ...)
#define PARAM_F32(name, ...)
PARAM_LIST
PARAM_U64_ENUM(NUM_OF)
#undef PARAM_U8
#undef PARAM_I8
#undef PARAM_U16
#undef PARAM_I16
#undef PARAM_U32
#undef PARAM_I32
#undef PARAM_U64
#undef PARAM_I64
#undef PARAM_F32
} param_u64_t;
// i64
typedef enum
{
#define PARAM_U8(name, ...)
#define PARAM_I8(name, ...)
#define PARAM_U16(name, ...)
#define PARAM_I16(name, ...)
#define PARAM_U32(name, ...)
#define PARAM_I32(name, ...)
#define PARAM_U64(name, ...)
#define PARAM_I64(name, ...) PARAM_I64_ENUM(name),
#define PARAM_F32(name, ...)
PARAM_LIST
PARAM_I64_ENUM(NUM_OF)
#undef PARAM_U8
#undef PARAM_I8
#undef PARAM_U16
#undef PARAM_I16
#undef PARAM_U32
#undef PARAM_I32
#undef PARAM_U64
#undef PARAM_I64
#undef PARAM_F32
} param_i64_t;
// f32
typedef enum
{
#define PARAM_U8(name, ...)
#define PARAM_I8(name, ...)
#define PARAM_U16(name, ...)
#define PARAM_I16(name, ...)
#define PARAM_U32(name, ...)
#define PARAM_I32(name, ...)
#define PARAM_U64(name, ...)
#define PARAM_I64(name, ...)
#define PARAM_F32(name, ...) PARAM_F32_ENUM(name),
PARAM_LIST
PARAM_F32_ENUM(NUM_OF)
#undef PARAM_U8
#undef PARAM_I8
#undef PARAM_U16
#undef PARAM_I16
#undef PARAM_U32
#undef PARAM_I32
#undef PARAM_U64
#undef PARAM_I64
#undef PARAM_F32
} param_ft32_t;
// Define extern variables for info and value arrays
// this is only required if we want to have static inline get/set functions API functions in header
// otherwise if not we can have these variables hidden in source file and not exposed in header
//
// info var must be exposed only if we are doing parameter min/max checks here in API functions in header
#define PARAM_INFO_VAR_NAME(postfix) PARAM_INFO_TYPENAME(postfix) g_param_ ## postfix ## _info_array
extern const PARAM_INFO_VAR_NAME(u8)[];
extern const PARAM_INFO_VAR_NAME(i8)[];
extern const PARAM_INFO_VAR_NAME(u16)[];
extern const PARAM_INFO_VAR_NAME(i16)[];
extern const PARAM_INFO_VAR_NAME(u32)[];
extern const PARAM_INFO_VAR_NAME(i32)[];
extern const PARAM_INFO_VAR_NAME(u64)[];
extern const PARAM_INFO_VAR_NAME(i64)[];
extern const PARAM_INFO_VAR_NAME(f32)[];
#define PARAM_VAL_VAR_NAME(postfix) PARAM_VAL_TYPENAME(postfix) g_param_ ## postfix ## _val_array
extern PARAM_VAL_VAR_NAME(u8)[];
extern PARAM_VAL_VAR_NAME(i8)[];
extern PARAM_VAL_VAR_NAME(u16)[];
extern PARAM_VAL_VAR_NAME(i16)[];
extern PARAM_VAL_VAR_NAME(u32)[];
extern PARAM_VAL_VAR_NAME(i32)[];
extern PARAM_VAL_VAR_NAME(u64)[];
extern PARAM_VAL_VAR_NAME(i64)[];
extern PARAM_VAL_VAR_NAME(f32)[];
//
//
#define PARAM_CHECK(p_param_info, val) (((val) >= p_param_info->min) && ((val) <= p_param_info->max))
#define PARAM_SET(p_param_val, p_param_info, val) \
do \
{ \
ASSERT(param_check(p_param_info, val)); \
atomic_store_explicit(p_param_val, val, memory_order_relaxed); \
} while (0)
#define PARAM_GET(p_param_val, val) atomic_load_explicit(p_param_val, memory_order_relaxed)
// Make and use macros/function per type so that:
// a) user is aware of what type the parameter has so he knows what typed variable to use
// b) type safety, if type of parameter changes compiler will emit error/warning, for example user uses
// param_set_u32() but parameter type changed from uint32_t to uint8_t (because ePARA_U32_XXX enum will no longer exist)
// c) extra type safety, because atomic_store_explicit() and atomic_load_explicit() are compiler builtins
// they only check that sizes between atomic pointer and value match and not also signdness
#define param_set_u8(param, val) param_set_u8_internal(PARAM_U8_ENUM(param), val)
#define param_set_i8(param, val) param_set_i8_internal(PARAM_I8_ENUM(param), val)
#define param_set_u16(param, val) param_set_u16_internal(PARAM_U16_ENUM(param), val)
#define param_set_i16(param, val) param_set_i16_internal(PARAM_I16_ENUM(param), val)
#define param_set_u32(param, val) param_set_u32_internal(PARAM_U32_ENUM(param), val)
#define param_set_i32(param, val) param_set_i32_internal(PARAM_I32_ENUM(param), val)
#define param_set_u64(param, val) param_set_u64_internal(PARAM_U64_ENUM(param), val)
#define param_set_i64(param, val) param_set_i64_internal(PARAM_I64_ENUM(param), val)
#define param_set_f32(param, val) param_set_f32_internal(PARAM_F32_ENUM(param), val)
//
#define param_get_u8(param) param_get_u8_internal(PARAM_U8_ENUM(param))
#define param_get_i8(param) param_get_i8_internal(PARAM_I8_ENUM(param))
#define param_get_u16(param) param_get_u16_internal(PARAM_U16_ENUM(param))
#define param_get_i16(param) param_get_i16_internal(PARAM_I16_ENUM(param))
#define param_get_u32(param) param_get_u32_internal(PARAM_U32_ENUM(param))
#define param_get_i32(param) param_get_i32_internal(PARAM_I32_ENUM(param))
#define param_get_u64(param) param_get_u64_internal(PARAM_U64_ENUM(param))
#define param_get_i64(param) param_get_i64_internal(PARAM_I64_ENUM(param))
#define param_get_f32(param) param_get_f32_internal(PARAM_F32_ENUM(param))
//
#define param_check_u8(param, val) param_check_u8_internal(PARAM_U8_ENUM(param), val)
#define param_check_i8(param, val) param_check_i8_internal(PARAM_I8_ENUM(param), val)
#define param_check_u16(param, val) param_check_u16_internal(PARAM_U16_ENUM(param), val)
#define param_check_i16(param, val) param_check_i16_internal(PARAM_I16_ENUM(param), val)
#define param_check_u32(param, val) param_check_u32_internal(PARAM_U32_ENUM(param), val)
#define param_check_i32(param, val) param_check_i32_internal(PARAM_I32_ENUM(param), val)
#define param_check_u64(param, val) param_check_u64_internal(PARAM_U64_ENUM(param), val)
#define param_check_i64(param, val) param_check_i64_internal(PARAM_I64_ENUM(param), val)
#define param_check_f32(param, val) param_check_f32_internal(PARAM_F32_ENUM(param), val)
//
static inline void param_set_u8_internal(param_u8_t param, uint8_t val) { PARAM_SET(&PARAM_VAL_VAR_NAME(u8)[param], &PARAM_INFO_VAR_NAME(u8)[param], val); }
static inline void param_set_i8_internal(param_i8_t param, int8_t val) { PARAM_SET(&PARAM_VAL_VAR_NAME(i8)[param], &PARAM_INFO_VAR_NAME(i8)[param], val); }
static inline void param_set_u16_internal(param_u16_t param, uint16_t val) { PARAM_SET(&PARAM_VAL_VAR_NAME(u16)[param], &PARAM_INFO_VAR_NAME(u16)[param], val); }
static inline void param_set_i16_internal(param_i16_t param, int16_t val) { PARAM_SET(&PARAM_VAL_VAR_NAME(i16)[param], &PARAM_INFO_VAR_NAME(i16)[param], val); }
static inline void param_set_u32_internal(param_u32_t param, uint32_t val) { PARAM_SET(&PARAM_VAL_VAR_NAME(u32)[param], &PARAM_INFO_VAR_NAME(u32)[param], val); }
static inline void param_set_i32_internal(param_i32_t param, int32_t val) { PARAM_SET(&PARAM_VAL_VAR_NAME(i32)[param], &PARAM_INFO_VAR_NAME(i32)[param], val); }
static inline void param_set_u64_internal(param_u64_t param, uint64_t val) { PARAM_SET(&PARAM_VAL_VAR_NAME(u64)[param], &PARAM_INFO_VAR_NAME(u64)[param], val); }
static inline void param_set_i64_internal(param_i64_t param, int64_t val) { PARAM_SET(&PARAM_VAL_VAR_NAME(i64)[param], &PARAM_INFO_VAR_NAME(i64)[param], val); }
static inline void param_set_f32_internal(param_f32_t param, float32_t val) { PARAM_SET(&PARAM_VAL_VAR_NAME(f32)[param], &PARAM_INFO_VAR_NAME(f32)[param], val); }
//
static inline uint8_t param_get_u8_internal(param_u8_t param) { return PARAM_GET(&PARAM_VAL_VAR_NAME(u8)[param]); }
static inline int8_t param_get_i8_internal(param_i8_t param) { return PARAM_GET(&PARAM_VAL_VAR_NAME(i8)[param]); }
static inline uint16_t param_get_u16_internal(param_u16_t param) { return PARAM_GET(&PARAM_VAL_VAR_NAME(u16)[param]); }
static inline int16_t param_get_i16_internal(param_i16_t param) { return PARAM_GET(&PARAM_VAL_VAR_NAME(i16)[param]); }
static inline uint32_t param_get_u32_internal(param_u32_t param) { return PARAM_GET(&PARAM_VAL_VAR_NAME(u32)[param]); }
static inline int32_t param_get_i32_internal(param_i32_t param) { return PARAM_GET(&PARAM_VAL_VAR_NAME(i32)[param]); }
static inline uint64_t param_get_u64_internal(param_u64_t param) { return PARAM_GET(&PARAM_VAL_VAR_NAME(u64)[param]); }
static inline int64_t param_get_i64_internal(param_i64_t param) { return PARAM_GET(&PARAM_VAL_VAR_NAME(i64)[param]); }
static inline float32_t param_get_f32_internal(param_ft32_t param) { return PARAM_GET(&PARAM_VAL_VAR_NAME(f32)[param]); }
//
static inline bool param_check_u8_internal(param_u8_t param, uint8_t val) { return PARAM_CHECK(&PARAM_INFO_VAR_NAME(u8)[param], val); }
static inline bool param_check_i8_internal(param_i8_t param, int8_t val) { return PARAM_CHECK(&PARAM_INFO_VAR_NAME(i8)[param], val); }
static inline bool param_check_u16_internal(param_u16_t param, uint16_t val) { return PARAM_CHECK(&PARAM_INFO_VAR_NAME(u16)[param], val); }
static inline bool param_check_i16_internal(param_i16_t param, int16_t val) { return PARAM_CHECK(&PARAM_INFO_VAR_NAME(i16)[param], val); }
static inline bool param_check_u32_internal(param_u32_t param, uint32_t val) { return PARAM_CHECK(&PARAM_INFO_VAR_NAME(u32)[param], val); }
static inline bool param_check_i32_internal(param_i32_t param, int32_t val) { return PARAM_CHECK(&PARAM_INFO_VAR_NAME(i32)[param], val); }
static inline bool param_check_u64_internal(param_u64_t param, uint64_t val) { return PARAM_CHECK(&PARAM_INFO_VAR_NAME(u64)[param], val); }
static inline bool param_check_i64_internal(param_i64_t param, int64_t val) { return PARAM_CHECK(&PARAM_INFO_VAR_NAME(i64)[param], val); }
static inline bool param_check_f32_internal(param_f32_t param, float32_t val) { return PARAM_CHECK(&PARAM_INFO_VAR_NAME(f32)[param], val); }
#endif // PARAM_H_
///////////////////////////////////////////////////////////////////////
// param_cfg.h
///////////////////////////////////////////////////////////////////////
#ifndef PARAM_CFG_H_
#define PARAM_CFG_H_
// NOTE: type is specified with macro name
#define PARAM_LIST \
PARAM_U8(MY_PARAM_A, 100, 0, 100, 12) \
PARAM_I32(MY_PARAM_B, 200, -123, 123, 0) \
PARAM_U16(MY_PARAM_C, 300, 1000, 2000, 1000) \
PARAM_F32(MY_PARAM_D, 400, -1.f, 5.f, 3.3f)
#endif // PARAM_CFG_H_
///////////////////////////////////////////////////////////////////////
// param.c
///////////////////////////////////////////////////////////////////////
#include "param.h"
// Define all parameters in a single enum so that we can detect duplicates
// for example if same named parameter was declared as U32 and U8 parameter
// this will trigger compiler error
// This enum is not part of API and is not used for anything other then detecting
// parameter duplicates
#define PARAM_ANY_ENUM(name) PARAM_ENUM(ANY, name)
typedef enum
{
#define PARAM_U8(name, ...) PARAM_ANY_ENUM(name),
#define PARAM_I8(name, ...) PARAM_ANY_ENUM(name),
#define PARAM_U16(name, ...) PARAM_ANY_ENUM(name),
#define PARAM_I16(name, ...) PARAM_ANY_ENUM(name),
#define PARAM_U32(name, ...) PARAM_ANY_ENUM(name),
#define PARAM_I32(name, ...) PARAM_ANY_ENUM(name),
#define PARAM_U64(name, ...) PARAM_ANY_ENUM(name),
#define PARAM_I64(name, ...) PARAM_ANY_ENUM(name),
#define PARAM_F32(name, ...) PARAM_ANY_ENUM(name),
PARAM_LIST
#undef PARAM_U8
#undef PARAM_I8
#undef PARAM_U16
#undef PARAM_I16
#undef PARAM_U32
#undef PARAM_I32
#undef PARAM_U64
#undef PARAM_I64
#undef PARAM_F32
} param_any_t;
// Define parameter value and info arrays for all types
//
// if we make these variables globals then we can have static inline API functions in header file
// otherwise if these variables are static then the API functions must be extern
//
// u8
const PARAM_INFO_VAR_NAME(u8)[] =
{
#define PARAM_U8(name, id_, min_, max_, def_) [PARAM_U8_ENUM(name)] = {.id = id_, .min = min_, .max = max_, .def = def_},
PARAM_LIST
#undef PARAM_U8
};
PARAM_VAL_VAR_NAME(u8)[] =
{
#define PARAM_U8(name, id_, min_, max_, def_) [PARAM_U8_ENUM(name)] = def_,
PARAM_LIST
#undef PARAM_U8
};
// i8
const PARAM_INFO_VAR_NAME(i8)[] =
{
#define PARAM_I8(name, id_, min_, max_, def_) [PARAM_I8_ENUM(name)] = {.id = id_, .min = min_, .max = max_, .def = def_},
PARAM_LIST
#undef PARAM_I8
};
PARAM_VAL_VAR_NAME(i8)[] =
{
#define PARAM_I8(name, id_, min_, max_, def_) [PARAM_I8_ENUM(name)] = def_,
PARAM_LIST
#undef PARAM_I8
};
// u16
const PARAM_INFO_VAR_NAME(u16)[] =
{
#define PARAM_U16(name, id_, min_, max_, def_) [PARAM_U16_ENUM(name)] = {.id = id_, .min = min_, .max = max_, .def = def_},
PARAM_LIST
#undef PARAM_U16
};
PARAM_VAL_VAR_NAME(u16)[] =
{
#define PARAM_U16(name, id_, min_, max_, def_) [PARAM_U16_ENUM(name)] = def_,
PARAM_LIST
#undef PARAM_U16
};
// i16
const PARAM_INFO_VAR_NAME(i16)[] =
{
#define PARAM_I16(name, id_, min_, max_, def_) [PARAM_I16_ENUM(name)] = {.id = id_, .min = min_, .max = max_, .def = def_},
PARAM_LIST
#undef PARAM_I16
};
PARAM_VAL_VAR_NAME(i16)[] =
{
#define PARAM_I16(name, id_, min_, max_, def_) [PARAM_I16_ENUM(name)] = def_,
PARAM_LIST
#undef PARAM_I16
};
// u32
const PARAM_INFO_VAR_NAME(u32)[] =
{
#define PARAM_U32(name, id_, min_, max_, def_) [PARAM_U32_ENUM(name)] = {.id = id_, .min = min_, .max = max_, .def = def_},
PARAM_LIST
#undef PARAM_U32
};
PARAM_VAL_VAR_NAME(u32)[] =
{
#define PARAM_U32(name, id_, min_, max_, def_) [PARAM_U32_ENUM(name)] = def_,
PARAM_LIST
#undef PARAM_U32
};
// i32
const PARAM_INFO_VAR_NAME(i32)[] =
{
#define PARAM_I32(name, id_, min_, max_, def_) [PARAM_I32_ENUM(name)] = {.id = id_, .min = min_, .max = max_, .def = def_},
PARAM_LIST
#undef PARAM_I32
};
PARAM_VAL_VAR_NAME(i32)[] =
{
#define PARAM_I32(name, id_, min_, max_, def_) [PARAM_I32_ENUM(name)] = def_,
PARAM_LIST
#undef PARAM_I32
};
// u64
const PARAM_INFO_VAR_NAME(u64)[] =
{
#define PARAM_U64(name, id_, min_, max_, def_) [PARAM_U64_ENUM(name)] = {.id = id_, .min = min_, .max = max_, .def = def_},
PARAM_LIST
#undef PARAM_U64
};
PARAM_VAL_VAR_NAME(u64)[] =
{
#define PARAM_U64(name, id_, min_, max_, def_) [PARAM_U64_ENUM(name)] = def_,
PARAM_LIST
#undef PARAM_U64
};
// i64
const PARAM_INFO_VAR_NAME(i64)[] =
{
#define PARAM_I64(name, id_, min_, max_, def_) [PARAM_I64_ENUM(name)] = {.id = id_, .min = min_, .max = max_, .def = def_},
PARAM_LIST
#undef PARAM_I64
};
PARAM_VAL_VAR_NAME(i64)[] =
{
#define PARAM_I64(name, id_, min_, max_, def_) [PARAM_I64_ENUM(name)] = def_,
PARAM_LIST
#undef PARAM_I64
};
// f32
const PARAM_INFO_VAR_NAME(f32)[] =
{
#define PARAM_F32(name, id_, min_, max_, def_) [PARAM_F32_ENUM(name)] = {.id = id_, .min = min_, .max = max_, .def = def_},
PARAM_LIST
#undef PARAM_F32
};
PARAM_VAL_VAR_NAME(f32)[] =
{
#define PARAM_F32(name, id_, min_, max_, def_) [PARAM_F32_ENUM(name)] = def_,
PARAM_LIST
#undef PARAM_F32
};
///////////////////////////////////////////////////////////////////////
// main.c
///////////////////////////////////////////////////////////////////////
#include "param.h"
void main(void)
{
// We don't have to add ePARAM_ prefix, instead just use parameter name as defined in param_cfg.h
//
param_set_u8(MY_PARAM_A, 30);
float32_t val = param_get_f32(MY_PARAM_D);
if (!param_check_i32(MY_PARAM_B, 1000))
{
printf("error");
}
}
//*********************
// Drawbacks:
// 1. messy code with a lot #define #undef due to X macros when declaring enums and arrays
// 2. relies on GCC compiler extension to have 0 length arrays (in case no parameters for some specific type)
Following code proposed by @tripping-code: