Конфигурацията на линкера:
SECTIONS
{
.events :
{
__events_start = .;
KEEP(*(SORT(.events*)));
__events_end = .;
}
.event_handlers :
{
__event_handlers_start = .;
KEEP(*(SORT(.event_handlers*)));
__event_handlers_end = .;
}
}
# Keep INSERT AFTER to append this linker script to the default one.
# See https://www.sourceware.org/binutils/docs/ld/Miscellaneous-Commands.
INSERT AFTER .text;
Хедър файла на евънта:
#define EVENTS_SECTION ".events"
#define EVENTS_HANDLER_SECTION ".event_handlers"
#define __EVENT_DECLARE(_type, _event, _value_t, _value, _default, _set, _get) \
\
typedef _type _value_t; \
\
extern _value_t _value; \
extern _value_t _default; \
\
extern event_t _event; \
\
static inline void _set(_type value) \
{ \
_type old = _value; \
_value = value; \
event_notify(&_event, &old, &value); \
} \
\
static inline _type _get(void) \
{ \
return _value; \
}
#define _EVENT_DECLARE(_name, _type) \
__EVENT_DECLARE( \
_type, \
CONCAT_N(__, _name, _event), \
CONCAT_N(__, _name, _value_t), \
CONCAT_N(__, _name, _value), \
CONCAT_N(__, _name, _default), \
CONCAT_N(_name, _set), \
CONCAT_N(_name, _get))
#define __EVENT_IMPLEMENT(_name, _type, _default_value, _persistent, _event, _value_t, _value, _default) \
\
_value_t _value = _default_value; \
_value_t _default = _default_value; \
\
event_t _event __attribute__((section(EVENTS_SECTION))) = { \
.name = #_name, \
.value = &_value, \
.default_value = &_default, \
.size = sizeof(_value), \
.is_persistent = _persistent \
};
#define _EVENT_IMPLEMENT(_name, _type, _default_value, _persistent) \
__EVENT_IMPLEMENT( \
_name, \
_type, \
_default_value, \
_persistent, \
CONCAT_N(__, _name, _event), \
CONCAT_N(__, _name, _value_t), \
CONCAT_N(__, _name, _value), \
CONCAT_N(__, _name, _default))
#define __EVENT_SUBSCRIBE(_event, _handler, _wrapper, _list, _value_t) \
static void _wrapper(const void* const old_value, const void* const new_value) \
{ \
_handler((const _value_t* const)old_value, (const _value_t* const)new_value); \
} \
\
event_handler_t _list __attribute__((__used__, section(EVENTS_HANDLER_SECTION))) = { \
.event = &_event, \
.handler = _wrapper \
}
#define _EVENT_SUBSCRIBE(_name, _handler) \
__EVENT_SUBSCRIBE( \
CONCAT_N(__, _name, _event), \
_handler, \
CONCAT_N(__, _name, _wrapper_, __LINE__), \
CONCAT_N(__, _name, _list_, __LINE__), \
CONCAT_N(__, _name, _value_t))
Имплементация за всички евънти:
void event_notify(const event_t* const event, const void* const old_value, const void* const new_value)
{
if (!notifications_enabled)
return;
if (event->is_persistent)
{
/* Take a copy of the handler to avoid NULL pointer assignment from another thread */
void (*persistent_handler_copy)(const event_t* const event, const void* const value) = persistent_handler;
if (persistent_handler_copy != NULL)
persistent_handler_copy(event, new_value);
}
BP_LOG_DEBUG("Looking for handlers for %s", event->name);
/* cppcheck-suppress comparePointers */
for (const event_handler_t* event_handler = __event_handlers_start; event_handler < __event_handlers_end; event_handler++)
{
BP_LOG_DEBUG("Calling handler %s", event->name);
if (event_handler->event == event)
event_handler->handler(old_value, new_value);
}
}
И употреба:
Дефинираш си евънт някъде в хедър файл.
EVENT_DECLARE(system_tick_second, uint32_t);
В Ц файл правиш имплементация.
EVENT_IMPLEMENT(system_tick_second, uint32_t, 0);
Закачване на хендлър:
void pid_second_tick_callback(const uint32_t* const old, const uint32_t* const new)
{
...
}
EVENT_SUBSCRIBE(system_tick_second, pid_second_tick_callback);
Нотификация при нов евънт:
system_tick_second_set(sys_ticks++);