/** * DI Configuration Generic I/O Layer * @defgroup config Generic configuration * @{ */ #ifndef LIBDI_INCLUDE_CONFIG_H_ #define LIBDI_INCLUDE_CONFIG_H_ #include #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif struct di_config_ctx; /** Configuration item (di_config_item) default type field selector */ enum di_config_item_default_type { DI_CONFIG_ITEM_DEFAULT_TYPE_UNKNOWN = 0, /**< Unknown default type */ DI_CONFIG_ITEM_DEFAULT_TYPE_BOOL, /**< bool */ DI_CONFIG_ITEM_DEFAULT_TYPE_INT8, /**< int8_t */ DI_CONFIG_ITEM_DEFAULT_TYPE_INT16, /**< int16_t */ DI_CONFIG_ITEM_DEFAULT_TYPE_INT32, /**< int32_t */ DI_CONFIG_ITEM_DEFAULT_TYPE_INT64, /**< int64_t */ DI_CONFIG_ITEM_DEFAULT_TYPE_UINT8, /**< uint8_t */ DI_CONFIG_ITEM_DEFAULT_TYPE_UINT16, /**< uint16_t */ DI_CONFIG_ITEM_DEFAULT_TYPE_UINT32, /**< uint32_t */ DI_CONFIG_ITEM_DEFAULT_TYPE_UINT64, /**< uint64_t */ DI_CONFIG_ITEM_DEFAULT_TYPE_FLOAT, /**< float */ DI_CONFIG_ITEM_DEFAULT_TYPE_DOUBLE, /**< double */ DI_CONFIG_ITEM_DEFAULT_TYPE_STR, /**< string, null terminated */ DI_CONFIG_ITEM_DEFAULT_TYPE_BLOB /**< blob, binary data */ }; /** * @name Item default value * @{ */ #define DI_CONFIG_ITEM_DEFAULT_BOOL(value) DI_CONFIG_ITEM_DEFAULT_TYPE_BOOL, { .b = (value) } #define DI_CONFIG_ITEM_DEFAULT_INT8(value) DI_CONFIG_ITEM_DEFAULT_TYPE_INT8, { .s8 = (value) } #define DI_CONFIG_ITEM_DEFAULT_INT16(value) DI_CONFIG_ITEM_DEFAULT_TYPE_INT16, { .s16 = (value) } #define DI_CONFIG_ITEM_DEFAULT_INT32(value) DI_CONFIG_ITEM_DEFAULT_TYPE_INT32, { .s32 = (value) } #define DI_CONFIG_ITEM_DEFAULT_INT64(value) DI_CONFIG_ITEM_DEFAULT_TYPE_INT64, { .s64 = (value) } #define DI_CONFIG_ITEM_DEFAULT_UINT8(value) DI_CONFIG_ITEM_DEFAULT_TYPE_UINT8, { .u8 = (value) } #define DI_CONFIG_ITEM_DEFAULT_UINT16(value) DI_CONFIG_ITEM_DEFAULT_TYPE_UINT16, { .u16 = (value) } #define DI_CONFIG_ITEM_DEFAULT_UINT32(value) DI_CONFIG_ITEM_DEFAULT_TYPE_UINT32, { .u32 = (value) } #define DI_CONFIG_ITEM_DEFAULT_UINT64(value) DI_CONFIG_ITEM_DEFAULT_TYPE_UINT64, { .u64 = (value) } #define DI_CONFIG_ITEM_DEFAULT_FLOAT(value) DI_CONFIG_ITEM_DEFAULT_TYPE_FLOAT, { .f = (value) } #define DI_CONFIG_ITEM_DEFAULT_DOUBLE(value) DI_CONFIG_ITEM_DEFAULT_TYPE_DOUBLE, { .d = (value) } #define DI_CONFIG_ITEM_DEFAULT_STR(value) DI_CONFIG_ITEM_DEFAULT_TYPE_STR, { .str = (value) } #define DI_CONFIG_ITEM_DEFAULT_BLOB(value) DI_CONFIG_ITEM_DEFAULT_TYPE_BLOB, { .bin = (value) } /** @} */ /** * @name Lowlevel callbacks * @{ */ /** * Low-level driver data-read callback * @param ctx Configuration context * @param offset Read offset in bytes * @param data Address to read data into * @param size Size of data in bytes */ typedef di_errno_t (*di_config_read_cb_t)(struct di_config_ctx *ctx, uint32_t offset, void *data, size_t size); /** * Low-level driver data-write callback * @param ctx Configuration context * @param offset Write offset in bytes * @param data Address of data to write * @param size Size of data in bytes */ typedef di_errno_t (*di_config_write_cb_t)(struct di_config_ctx *ctx, uint32_t offset, const void *data, size_t size); /** * Low-level driver synchronize callback * @param ctx Configuration context */ typedef void (*di_config_sync_cb_t)(struct di_config_ctx *ctx); /** @} */ /** * Configuration item */ struct di_config_item { unsigned int uid; /**< Unique ID */ size_t size; /**< Size in bytes */ enum di_config_item_default_type type; /**< Item type */ union { bool b; /**< Boolean */ int8_t s8; /**< Signed integer 8bit */ int16_t s16; /**< Signed integer 16bit */ int32_t s32; /**< Signed integer 32bit */ int64_t s64; /**< Signed integer 64bit */ uint8_t u8; /**< Unsigned integer 8bit */ uint16_t u16; /**< Unsigned integer 16bit */ uint32_t u32; /**< Unsigned integer 32bit */ uint64_t u64; /**< Unsigned integer 64bit */ float f; /**< Single precision floating point */ double d; /**< Double precision floating point */ char *str; /**< Null terminated string */ uint8_t *bin; /**< Binary blob */ } def; /**< Default value */ }; /** * Configuration context */ struct di_config_ctx { size_t size; /**< Size in bytes of low-level storage */ di_config_read_cb_t read; /**< Low-level storage driver read callback */ di_config_write_cb_t write; /**< Low-level storage driver write callback */ di_config_sync_cb_t sync; /**< Low-level storage driver sync callback */ di_bsem_t lock; /**< Binary semaphore to guard the context */ struct di_array items; /**< Configuration items array (see struct di_config_item) */ void *private_data; /**< Application defined private data */ }; /** * @name Core Config Functions * @{ */ /** * Initialize the configuration context */ void di_config_init(struct di_config_ctx *ctx); /** * Set available configuration items * @param ctx Configuration context * @param items Item list * @param size Amount of items in list * @retval DNOK Items ok, no duplicates entries found * @retval DNE_PARAM Items invalid, probably due to duplicates */ di_errno_t di_config_set_items(struct di_config_ctx *ctx, const struct di_config_item *items, size_t size); /** Set size of lowlevel */ static inline void di_config_set_size(struct di_config_ctx *ctx, size_t size) { ctx->size = size; } static inline void di_config_set_read(struct di_config_ctx *ctx, di_config_read_cb_t read) { ctx->read = read; } static inline void di_config_set_write(struct di_config_ctx *ctx, di_config_write_cb_t write) { ctx->write = write; } static inline void di_config_set_sync(struct di_config_ctx *ctx, di_config_sync_cb_t sync) { ctx->sync = sync; } static inline void di_config_set_private_data(struct di_config_ctx *ctx, void *private_data) { ctx->private_data = private_data; } /** @} */ /** * @name Write Functions * @{ */ #ifndef __cplusplus /** * Set configuration item value * @param ctx Configuration context * @param uid Item unique id * @param val Item value (bool, intX_t, uintX_t, float, double, char *, const char *) */ #define di_config_set(ctx, uid, val) \ _Generic((val), \ bool * : _di_config_set(ctx, uid, (const uint8_t *)(val), sizeof(bool)), \ int8_t * : _di_config_set(ctx, uid, (const uint8_t *)(val), sizeof(int8_t)), \ int16_t * : _di_config_set(ctx, uid, (const uint8_t *)(val), sizeof(int16_t)), \ int32_t * : _di_config_set(ctx, uid, (const uint8_t *)(val), sizeof(int32_t)), \ int64_t * : _di_config_set(ctx, uid, (const uint8_t *)(val), sizeof(int64_t)), \ uint8_t * : _di_config_set(ctx, uid, (const uint8_t *)(val), sizeof(uint8_t)), \ uint16_t * : _di_config_set(ctx, uid, (const uint8_t *)(val), sizeof(uint16_t)), \ uint32_t * : _di_config_set(ctx, uid, (const uint8_t *)(val), sizeof(uint32_t)), \ uint64_t * : _di_config_set(ctx, uid, (const uint8_t *)(val), sizeof(uint64_t)), \ float * : _di_config_set(ctx, uid, (const uint8_t *)(val), sizeof(float)), \ double * : _di_config_set(ctx, uid, (const uint8_t *)(val), sizeof(double)), \ char * : _di_config_set(ctx, uid, (const uint8_t *)(val), 0U), \ const char * : _di_config_set(ctx, uid, (const uint8_t *)(val), 0U) \ ) #endif /** * Set data with size on requested unique id * @param ctx Configuration context * @param uid Item unique id * @param data Data to set * @param size Size of data * * @retval DNOK Set operation succesfull * @retval DNE_PARAM Invalid parameter (e.g set size is to big) * @retval DNE_NOTFOUND Configuration item not found * @retval DNE_OPDENIED Configuration item set denied due to low-level size to small (out-of-bound write) * * @note When size is smaller than the selected di_config_item.size the remaining size is filled with zero! * @note When size == 0, it is assumed data points to a null terminated string, then the size is automatically * calculated with strlen, and a extra byte is added to size to include the null byte (written by the fill). */ di_errno_t _di_config_set(struct di_config_ctx *ctx, unsigned int uid, const uint8_t *data, size_t size); /** * Set configuration item as binary blob * @param ctx Configuration context * @param uid Item unique id * @param blob Binary data blob * @param size Size of blob in bytes */ static inline di_errno_t di_config_set_blob(struct di_config_ctx *ctx, unsigned int uid, const void *blob, size_t size) { return _di_config_set(ctx, uid, (const uint8_t *)blob, size); } /** * Set configuration item default value * @param ctx Configuration context * @param uid Item unique id */ di_errno_t di_config_set_default(struct di_config_ctx *ctx, unsigned int uid); /** @} */ /** * @name Read Functions * @{ */ #ifndef __cplusplus /** * Get primitive configuration item value * @param ctx Configuration context * @param uid Item unique id * @param val Item value address (bool, intX_t, uintX_t, float, double) */ #define di_config_get(ctx, uid, val) \ _Generic((val), \ bool * : _di_config_get(ctx, uid, (uint8_t *)val, sizeof(bool)), \ int8_t * : _di_config_get(ctx, uid, (uint8_t *)val, sizeof(int8_t)), \ int16_t * : _di_config_get(ctx, uid, (uint8_t *)val, sizeof(int16_t)), \ int32_t * : _di_config_get(ctx, uid, (uint8_t *)val, sizeof(int32_t)), \ int64_t * : _di_config_get(ctx, uid, (uint8_t *)val, sizeof(int64_t)), \ uint8_t * : _di_config_get(ctx, uid, (uint8_t *)val, sizeof(uint8_t)), \ uint16_t * : _di_config_get(ctx, uid, (uint8_t *)val, sizeof(uint16_t)), \ uint32_t * : _di_config_get(ctx, uid, (uint8_t *)val, sizeof(uint32_t)), \ uint64_t * : _di_config_get(ctx, uid, (uint8_t *)val, sizeof(uint64_t)), \ float * : _di_config_get(ctx, uid, (uint8_t *)val, sizeof(float)), \ double * : _di_config_get(ctx, uid, (uint8_t *)val, sizeof(double)) \ ) /** * Get primitive configuration item value or load default * @param ctx Configuration context * @param uid Item unique id * @param val Item value address (bool, intX_t, uintX_t, float, double) */ #define di_config_get_or_load_default(ctx, uid, val) \ _Generic((val), \ bool * : _di_config_get_or_load_default(ctx, uid, (uint8_t *)val, sizeof(bool)), \ int8_t * : _di_config_get_or_load_default(ctx, uid, (uint8_t *)val, sizeof(int8_t)), \ int16_t * : _di_config_get_or_load_default(ctx, uid, (uint8_t *)val, sizeof(int16_t)), \ int32_t * : _di_config_get_or_load_default(ctx, uid, (uint8_t *)val, sizeof(int32_t)), \ int64_t * : _di_config_get_or_load_default(ctx, uid, (uint8_t *)val, sizeof(int64_t)), \ uint8_t * : _di_config_get_or_load_default(ctx, uid, (uint8_t *)val, sizeof(uint8_t)), \ uint16_t * : _di_config_get_or_load_default(ctx, uid, (uint8_t *)val, sizeof(uint16_t)), \ uint32_t * : _di_config_get_or_load_default(ctx, uid, (uint8_t *)val, sizeof(uint32_t)), \ uint64_t * : _di_config_get_or_load_default(ctx, uid, (uint8_t *)val, sizeof(uint64_t)), \ float * : _di_config_get_or_load_default(ctx, uid, (uint8_t *)val, sizeof(float)), \ double * : _di_config_get_or_load_default(ctx, uid, (uint8_t *)val, sizeof(double)) \ ) #endif /** * Get data with size on requested unique id * @param ctx Configuration context * @param uid Item unique id * @param data Address of data to read into * @param size Size of data * * @retval DNOK Get operation succesfull * @retval DNE_CHECKSUM Invalid item checksum * @retval DNE_PARAM Invalid parameter (e.g set size is to big or to small) * @retval DNE_NOTFOUND Configuration item not found * @retval DNE_OPDENIED Configuration item set denied due to low-level size to small (out-of-bound write) * * @note Data size must always be same size as configuration item due to crc checksum over whole item */ di_errno_t _di_config_get(struct di_config_ctx *ctx, unsigned int uid, uint8_t *data, size_t size); /** * Get configuration item as binary blob * @param ctx Configuration context * @param uid Item unique id * @param blob Address to store binary data blob * @param size Size of blob (must match the exact size of uid item) */ static inline di_errno_t di_config_get_blob(struct di_config_ctx *ctx, unsigned int uid, void *blob, size_t size) { return _di_config_get(ctx, uid, (uint8_t *)blob, size); } /** * Get data with size on requested unique id or load default value * It first tries to get the stored value, when the checksum is incorrect it writes the default value * and returns it. * @param ctx Configuration context * @param uid Item unique id * @param data Address of data to read into * @param size Size of data * * @retval DNOK Get operation succesfull * @retval DNE_PARAM Invalid parameter (e.g set size is to big or to small) * @retval DNE_NOTFOUND Configuration item not found * @retval DNE_OPDENIED Configuration item set denied due to low-level size to small (out-of-bound write) * * @note Data size must always be same size as configuration item due to crc checksum over whole item */ di_errno_t _di_config_get_or_load_default(struct di_config_ctx *ctx, unsigned int uid, uint8_t *data, size_t size); /** * Get string with exact size on requested unique id or load default string * It first tries to get the stored string, when the checksum is incorrect it writes the default value * and returns it. * @param ctx Configuration context * @param uid Item unique id * @param str Address of string * @param size Size of string * * @retval DNOK Get operation succesfull * @retval DNE_PARAM Invalid parameter (e.g set size is to big or to small) * @retval DNE_NOTFOUND Configuration item not found * @retval DNE_OPDENIED Configuration item set denied due to low-level size to small (out-of-bound write) * * @note Data size must always be same size as configuration item due to crc checksum over whole item */ di_errno_t di_config_get_or_load_default_string(struct di_config_ctx *ctx, unsigned int uid, char *str, size_t size); /** * Get configuration item as string * @param ctx Configuration context * @param uid Item unique id * @param str Address to store string * @param size Size of string buffer (must match the exact size of uid item) * * @retval DNOK Get operation succesfull * @retval DNE_CHECKSUM Invalid item checksum * @retval DNE_PARAM Invalid parameter (e.g set size is to big or to small) * @retval DNE_NOTFOUND Configuration item not found * @retval DNE_OPDENIED Configuration item set denied due to low-level size to small (out-of-bound write) * @note The item unique id is always filled with (remaining) zeros when writing. */ static inline di_errno_t di_config_get_string(struct di_config_ctx *ctx, unsigned int uid, char *str, size_t size) { return _di_config_get(ctx, uid, (uint8_t *)str, size); } /** @} */ #ifdef __cplusplus } #endif /* C++ compatible API where C11 has _Generic */ #ifdef __cplusplus /** Generic di_config_set for C++ */ static inline di_errno_t di_config_set(struct di_config_ctx *ctx, unsigned int uid, bool val) { return _di_config_set(ctx, uid, (const uint8_t *)&val, sizeof(bool)); } static inline di_errno_t di_config_set(struct di_config_ctx *ctx, unsigned int uid, int8_t val) { return _di_config_set(ctx, uid, (const uint8_t *)&val, sizeof(int8_t)); } static inline di_errno_t di_config_set(struct di_config_ctx *ctx, unsigned int uid, int16_t val) { return _di_config_set(ctx, uid, (const uint8_t *)&val, sizeof(int16_t)); } static inline di_errno_t di_config_set(struct di_config_ctx *ctx, unsigned int uid, int32_t val) { return _di_config_set(ctx, uid, (const uint8_t *)&val, sizeof(int32_t)); } static inline di_errno_t di_config_set(struct di_config_ctx *ctx, unsigned int uid, int64_t val) { return _di_config_set(ctx, uid, (const uint8_t *)&val, sizeof(int64_t)); } static inline di_errno_t di_config_set(struct di_config_ctx *ctx, unsigned int uid, uint8_t val) { return _di_config_set(ctx, uid, (const uint8_t *)&val, sizeof(uint8_t)); } static inline di_errno_t di_config_set(struct di_config_ctx *ctx, unsigned int uid, uint16_t val) { return _di_config_set(ctx, uid, (const uint8_t *)&val, sizeof(uint16_t)); } static inline di_errno_t di_config_set(struct di_config_ctx *ctx, unsigned int uid, uint32_t val) { return _di_config_set(ctx, uid, (const uint8_t *)&val, sizeof(uint32_t)); } static inline di_errno_t di_config_set(struct di_config_ctx *ctx, unsigned int uid, uint64_t val) { return _di_config_set(ctx, uid, (const uint8_t *)&val, sizeof(uint64_t)); } static inline di_errno_t di_config_set(struct di_config_ctx *ctx, unsigned int uid, float val) { return _di_config_set(ctx, uid, (const uint8_t *)&val, sizeof(float)); } static inline di_errno_t di_config_set(struct di_config_ctx *ctx, unsigned int uid, double val) { return _di_config_set(ctx, uid, (const uint8_t *)&val, sizeof(double)); } static inline di_errno_t di_config_set(struct di_config_ctx *ctx, unsigned int uid, char *val) { return _di_config_set(ctx, uid, (const uint8_t *)val, 0); } static inline di_errno_t di_config_set(struct di_config_ctx *ctx, unsigned int uid, const char *val) { return _di_config_set(ctx, uid, (const uint8_t *)val, 0); } /** Generic di_config_get for C++ */ static inline di_errno_t di_config_get(struct di_config_ctx *ctx, unsigned int uid, bool *val) { return _di_config_get(ctx, uid, (uint8_t *)val, sizeof(bool)); } static inline di_errno_t di_config_get(struct di_config_ctx *ctx, unsigned int uid, int8_t *val) { return _di_config_get(ctx, uid, (uint8_t *)val, sizeof(int8_t)); } static inline di_errno_t di_config_get(struct di_config_ctx *ctx, unsigned int uid, int16_t *val) { return _di_config_get(ctx, uid, (uint8_t *)val, sizeof(int16_t)); } static inline di_errno_t di_config_get(struct di_config_ctx *ctx, unsigned int uid, int32_t *val) { return _di_config_get(ctx, uid, (uint8_t *)val, sizeof(int32_t)); } static inline di_errno_t di_config_get(struct di_config_ctx *ctx, unsigned int uid, int64_t *val) { return _di_config_get(ctx, uid, (uint8_t *)val, sizeof(int64_t)); } static inline di_errno_t di_config_get(struct di_config_ctx *ctx, unsigned int uid, uint8_t *val) { return _di_config_get(ctx, uid, (uint8_t *)val, sizeof(uint8_t)); } static inline di_errno_t di_config_get(struct di_config_ctx *ctx, unsigned int uid, uint16_t *val) { return _di_config_get(ctx, uid, (uint8_t *)val, sizeof(uint16_t)); } static inline di_errno_t di_config_get(struct di_config_ctx *ctx, unsigned int uid, uint32_t *val) { return _di_config_get(ctx, uid, (uint8_t *)val, sizeof(uint32_t)); } static inline di_errno_t di_config_get(struct di_config_ctx *ctx, unsigned int uid, uint64_t *val) { return _di_config_get(ctx, uid, (uint8_t *)val, sizeof(uint64_t)); } static inline di_errno_t di_config_get(struct di_config_ctx *ctx, unsigned int uid, float *val) { return _di_config_get(ctx, uid, (uint8_t *)val, sizeof(float)); } static inline di_errno_t di_config_get(struct di_config_ctx *ctx, unsigned int uid, double *val) { return _di_config_get(ctx, uid, (uint8_t *)val, sizeof(double)); } /** Generic di_config_get_or_load_default for C++ */ static inline di_errno_t di_config_get_or_load_default(struct di_config_ctx *ctx, unsigned int uid, bool *val) { return _di_config_get_or_load_default(ctx, uid, (uint8_t *)val, sizeof(bool)); } static inline di_errno_t di_config_get_or_load_default(struct di_config_ctx *ctx, unsigned int uid, int8_t *val) { return _di_config_get_or_load_default(ctx, uid, (uint8_t *)val, sizeof(int8_t)); } static inline di_errno_t di_config_get_or_load_default(struct di_config_ctx *ctx, unsigned int uid, int16_t *val) { return _di_config_get_or_load_default(ctx, uid, (uint8_t *)val, sizeof(int16_t)); } static inline di_errno_t di_config_get_or_load_default(struct di_config_ctx *ctx, unsigned int uid, int32_t *val) { return _di_config_get_or_load_default(ctx, uid, (uint8_t *)val, sizeof(int32_t)); } static inline di_errno_t di_config_get_or_load_default(struct di_config_ctx *ctx, unsigned int uid, int64_t *val) { return _di_config_get_or_load_default(ctx, uid, (uint8_t *)val, sizeof(int64_t)); } static inline di_errno_t di_config_get_or_load_default(struct di_config_ctx *ctx, unsigned int uid, uint8_t *val) { return _di_config_get_or_load_default(ctx, uid, (uint8_t *)val, sizeof(uint8_t)); } static inline di_errno_t di_config_get_or_load_default(struct di_config_ctx *ctx, unsigned int uid, uint16_t *val) { return _di_config_get_or_load_default(ctx, uid, (uint8_t *)val, sizeof(uint16_t)); } static inline di_errno_t di_config_get_or_load_default(struct di_config_ctx *ctx, unsigned int uid, uint32_t *val) { return _di_config_get_or_load_default(ctx, uid, (uint8_t *)val, sizeof(uint32_t)); } static inline di_errno_t di_config_get_or_load_default(struct di_config_ctx *ctx, unsigned int uid, uint64_t *val) { return _di_config_get_or_load_default(ctx, uid, (uint8_t *)val, sizeof(uint64_t)); } static inline di_errno_t di_config_get_or_load_default(struct di_config_ctx *ctx, unsigned int uid, float *val) { return _di_config_get_or_load_default(ctx, uid, (uint8_t *)val, sizeof(float)); } static inline di_errno_t di_config_get_or_load_default(struct di_config_ctx *ctx, unsigned int uid, double *val) { return _di_config_get_or_load_default(ctx, uid, (uint8_t *)val, sizeof(double)); } #endif /** @} */ #endif /* LIBDI_INCLUDE_CONFIG_H_ */