feat(msg): add publisher-subscriber messaging
This commit is contained in:
@@ -42,6 +42,10 @@ void lv_extra_init(void)
|
||||
lv_grid_init();
|
||||
#endif
|
||||
|
||||
#if LV_USE_MSG
|
||||
lv_msg_init();
|
||||
#endif
|
||||
|
||||
#if LV_USE_FS_FATFS != '\0'
|
||||
lv_fs_fatfs_init();
|
||||
#endif
|
||||
|
||||
@@ -18,6 +18,7 @@ extern "C" {
|
||||
#include "gridnav/lv_gridnav.h"
|
||||
#include "fragment/lv_fragment.h"
|
||||
#include "imgfont/lv_imgfont.h"
|
||||
#include "msg/lv_msg.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
|
||||
179
src/extra/others/msg/lv_msg.c
Normal file
179
src/extra/others/msg/lv_msg.c
Normal file
@@ -0,0 +1,179 @@
|
||||
/**
|
||||
* @file lv_msg.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_msg.h"
|
||||
#if LV_USE_MSG
|
||||
|
||||
#include "../../../misc/lv_assert.h"
|
||||
#include "../../../misc/lv_ll.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct {
|
||||
uint32_t msg_id;
|
||||
lv_msg_subscribe_cb_t callback;
|
||||
void * user_data;
|
||||
void * _priv_data; /*Internal: used only store 'obj' in lv_obj_subscribe*/
|
||||
} sub_dsc_t;
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static void notify(lv_msg_t * m);
|
||||
static void obj_notify_cb(void * s, lv_msg_t * m);
|
||||
static void obj_delete_event_cb(lv_event_t * e);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
static lv_ll_t subs_ll;
|
||||
static lv_ll_t reqs_ll;
|
||||
|
||||
/**********************
|
||||
* GLOBAL VARIABLES
|
||||
**********************/
|
||||
lv_event_code_t LV_EVENT_MSG_RECEIVED;
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_msg_init(void)
|
||||
{
|
||||
LV_EVENT_MSG_RECEIVED = lv_event_register_id();
|
||||
_lv_ll_init(&subs_ll, sizeof(sub_dsc_t));
|
||||
}
|
||||
|
||||
void * lv_msg_subsribe(uint32_t msg_id, lv_msg_subscribe_cb_t cb, void * user_data)
|
||||
{
|
||||
sub_dsc_t * s = _lv_ll_ins_tail(&subs_ll);
|
||||
LV_ASSERT_MALLOC(s);
|
||||
if(s == NULL) return NULL;
|
||||
|
||||
lv_memset_00(s, sizeof(*s));
|
||||
|
||||
s->msg_id = msg_id;
|
||||
s->callback = cb;
|
||||
s->user_data = user_data;
|
||||
return s;
|
||||
}
|
||||
|
||||
void * lv_msg_subsribe_obj(uint32_t msg_id, lv_obj_t * obj, void * user_data)
|
||||
{
|
||||
sub_dsc_t * s = lv_msg_subsribe(msg_id, obj_notify_cb, user_data);
|
||||
if(s == NULL) return NULL;
|
||||
s->_priv_data = obj;
|
||||
|
||||
/*If not added yet, add a delete event cb which automatically unsubcribes the object*/
|
||||
sub_dsc_t * s_first = lv_obj_get_event_user_data(obj, obj_delete_event_cb);
|
||||
if(s_first == NULL) {
|
||||
lv_obj_add_event_cb(obj, obj_delete_event_cb, LV_EVENT_DELETE, s);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
void lv_msg_unsubscribe(void * s)
|
||||
{
|
||||
LV_ASSERT_NULL(s);
|
||||
_lv_ll_remove(&subs_ll, s);
|
||||
lv_mem_free(s);
|
||||
}
|
||||
|
||||
uint32_t lv_msg_id_range(uint32_t start, uint32_t end)
|
||||
{
|
||||
if(start == end) return start;
|
||||
else return start + (end << 16);
|
||||
}
|
||||
|
||||
void lv_msg_send(uint32_t msg_id, const void * payload)
|
||||
{
|
||||
lv_msg_t m;
|
||||
lv_memset_00(&m, sizeof(m));
|
||||
m.id = msg_id;
|
||||
m.payload = payload;
|
||||
notify(&m);
|
||||
}
|
||||
|
||||
uint32_t lv_msg_get_id(lv_msg_t * m)
|
||||
{
|
||||
return m->id;
|
||||
}
|
||||
|
||||
const void * lv_msg_get_payload(lv_msg_t * m)
|
||||
{
|
||||
return m->payload;
|
||||
}
|
||||
|
||||
void * lv_msg_get_user_data(lv_msg_t * m)
|
||||
{
|
||||
return m->user_data;
|
||||
}
|
||||
|
||||
lv_msg_t * lv_event_get_msg(lv_event_t * e)
|
||||
{
|
||||
if(e->code == LV_EVENT_MSG_RECEIVED) {
|
||||
return lv_event_get_param(e);
|
||||
}
|
||||
else {
|
||||
LV_LOG_WARN("Not interpreted with this event code");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void notify(lv_msg_t * m)
|
||||
{
|
||||
sub_dsc_t * s;
|
||||
_LV_LL_READ(&subs_ll, s) {
|
||||
if(s->msg_id == m->id && s->callback) {
|
||||
m->user_data = s->user_data;
|
||||
m->_priv_data = s->_priv_data;
|
||||
s->callback(s, m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void obj_notify_cb(void * s, lv_msg_t * m)
|
||||
{
|
||||
LV_UNUSED(s);
|
||||
lv_event_send(m->_priv_data, LV_EVENT_MSG_RECEIVED, m);
|
||||
}
|
||||
|
||||
static void obj_delete_event_cb(lv_event_t * e)
|
||||
{
|
||||
lv_obj_t * obj = lv_event_get_target(e);
|
||||
|
||||
sub_dsc_t * s = _lv_ll_get_head(&subs_ll);
|
||||
sub_dsc_t * s_next;
|
||||
while(s) {
|
||||
/*On unsubscribe the list changes s becomes invalid so get next item while it's surely valid*/
|
||||
s_next = _lv_ll_get_next(&subs_ll, s);
|
||||
if(s->_priv_data == obj) {
|
||||
lv_msg_unsubscribe(s);
|
||||
}
|
||||
s = s_next;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /*LV_USE_MSG*/
|
||||
124
src/extra/others/msg/lv_msg.h
Normal file
124
src/extra/others/msg/lv_msg.h
Normal file
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* @file lv_msg.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_MSG_H
|
||||
#define LV_MSG_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../../../core/lv_obj.h"
|
||||
#if LV_USE_MSG
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct {
|
||||
uint32_t id; /*Identifier of the message*/
|
||||
void * user_data; /*Set the the user_data set in `lv_msg_subscribe`*/
|
||||
void * _priv_data; /*Used internally*/
|
||||
const void * payload; /*Pointer to the data of the message*/
|
||||
} lv_msg_t;
|
||||
|
||||
typedef void (*lv_msg_subscribe_cb_t)(void * s, lv_msg_t * msg);
|
||||
|
||||
typedef void (*lv_msg_request_cb_t)(void * r, uint32_t msg_id);
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Called internally to initialize the message module
|
||||
*/
|
||||
void lv_msg_init(void);
|
||||
|
||||
/**
|
||||
* Subscribe to an `msg_id`
|
||||
* @param msg_id the message ID to listen to
|
||||
* @param cb callback to call if a message with `msg_id` was sent
|
||||
* @param user_data arbitrary data which will be available in `cb` too
|
||||
* @return pointer to a "subscribe object". It can be used the unsubscribe.
|
||||
*/
|
||||
void * lv_msg_subsribe(uint32_t msg_id, lv_msg_subscribe_cb_t cb, void * user_data);
|
||||
|
||||
/**
|
||||
* Subscribe an `lv_obj` to a message.
|
||||
* `LV_EVENT_MSG_RECEIVED` will be triggered if a message with matching ID was sent
|
||||
* @param msg_id the message ID to listen to
|
||||
* @param obj pointer to an `lv_obj`
|
||||
* @param user_data arbitrary data which will be available in `cb` too
|
||||
* @return pointer to a "subscribe object". It can be used the unsubscribe.
|
||||
*/
|
||||
void * lv_msg_subsribe_obj(uint32_t msg_id, lv_obj_t * obj, void * user_data);
|
||||
|
||||
/**
|
||||
* Cancel a previous subscription
|
||||
* @param s pointer to a "subscibe object".
|
||||
* Return value of `lv_msg_subsribe` or `lv_msg_subsribe_obj`
|
||||
*/
|
||||
void lv_msg_unsubscribe(void * s);
|
||||
|
||||
/**
|
||||
* Send a message with a given ID and payload
|
||||
* @param msg_id ID of the message to send
|
||||
* @param data pointer to the data to send
|
||||
*/
|
||||
void lv_msg_send(uint32_t msg_id, const void * payload);
|
||||
|
||||
/**
|
||||
* Get the ID of a message object. Typically used in the subscriber callback.
|
||||
* @param m pointer to a message object
|
||||
* @return the ID of the message
|
||||
*/
|
||||
uint32_t lv_msg_get_id(lv_msg_t * m);
|
||||
|
||||
/**
|
||||
* Get the payload of a message object. Typically used in the subscriber callback.
|
||||
* @param m pointer to a message object
|
||||
* @return the payload of the message
|
||||
*/
|
||||
const void * lv_msg_get_payload(lv_msg_t * m);
|
||||
|
||||
/**
|
||||
* Get the user data of a message object. Typically used in the subscriber callback.
|
||||
* @param m pointer to a message object
|
||||
* @return the user data of the message
|
||||
*/
|
||||
void * lv_msg_get_user_data(lv_msg_t * m);
|
||||
|
||||
/**
|
||||
* Get the message object from an event object. Can be used in `LV_EVENT_MSG_RECEIVED` events.
|
||||
* @param e pointer to an event object
|
||||
* @return the message object or NULL if called with unrelated event code.
|
||||
*/
|
||||
lv_msg_t * lv_event_get_msg(lv_event_t * e);
|
||||
|
||||
/**********************
|
||||
* GLOBAL VARIABLES
|
||||
**********************/
|
||||
|
||||
extern lv_event_code_t LV_EVENT_MSG_RECEIVED;
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_MSG*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_MSG_H*/
|
||||
@@ -2167,7 +2167,7 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*draw img in label or span obj */
|
||||
/*1: Support using images as font in label or span widgets */
|
||||
#ifndef LV_USE_IMGFONT
|
||||
#ifdef CONFIG_LV_USE_IMGFONT
|
||||
#define LV_USE_IMGFONT CONFIG_LV_USE_IMGFONT
|
||||
@@ -2176,6 +2176,15 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*1: Enable a published subscriber based messaging system */
|
||||
#ifndef LV_USE_MSG
|
||||
#ifdef CONFIG_LV_USE_MSG
|
||||
#define LV_USE_MSG CONFIG_LV_USE_MSG
|
||||
#else
|
||||
#define LV_USE_MSG 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*==================
|
||||
* EXAMPLES
|
||||
*==================*/
|
||||
|
||||
Reference in New Issue
Block a user