fix(msg): make it work with Micropython (#3488)
* fix(msg): fill callback prototype lv_msg_subscribe_cb_t does not follow the callback conventions. Remove unused void* argument to fix that. * fix(msg): move subs_ll to gc roots * fix(msg): rename subsribe to subscribe * fix(msg): update docs * fix(msg): Add example_1 * fix(msg): fix include paths * fix(mgs): Fix python example typo and comments * fix(msg): LV_EVENT_MSG_RECEIVED event code
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# Messaging
|
||||
|
||||
Messaging (`lv_msg`) is a classic []publisher subscriber](https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern) implementation for LVGL.
|
||||
Messaging (`lv_msg`) is a classic [publisher subscriber](https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern) implementation for LVGL.
|
||||
|
||||
## IDs
|
||||
Both the publishers and the subscribers needs to know the message identifiers.
|
||||
@@ -33,9 +33,8 @@ lv_msg_send(MSG_USER_NAME_CHANGED, "John Smith");
|
||||
The callback should look like this:
|
||||
```c
|
||||
|
||||
static void user_name_subscriber_cb(void * s, lv_msg_t * m)
|
||||
static void user_name_subscriber_cb(lv_msg_t * m)
|
||||
{
|
||||
/*s: a subscriber obeject, can be used to unscubscribe*/
|
||||
/*m: a message object with the msg_id, payload, and user_data (set durung subscription)*/
|
||||
|
||||
...do something...
|
||||
|
||||
@@ -24,7 +24,7 @@ void lv_example_msg_1(void)
|
||||
lv_obj_align(label, LV_ALIGN_CENTER, 0, 30);
|
||||
|
||||
/*Subscribe the label to a message. Also use the user_data to set a format string here.*/
|
||||
lv_msg_subsribe_obj(MSG_NEW_TEMPERATURE, label, "%d °C");
|
||||
lv_msg_subscribe_obj(MSG_NEW_TEMPERATURE, label, "%d °C");
|
||||
}
|
||||
|
||||
static void slider_event_cb(lv_event_t * e)
|
||||
|
||||
39
examples/others/msg/lv_example_msg_1.py
Normal file
39
examples/others/msg/lv_example_msg_1.py
Normal file
@@ -0,0 +1,39 @@
|
||||
|
||||
# Define a message ID
|
||||
MSG_NEW_TEMPERATURE = const(1)
|
||||
|
||||
# Define the object that will be sent as msg payload
|
||||
class Temperature:
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
def __repr__(self):
|
||||
return f"{self.value} °C"
|
||||
|
||||
def slider_event_cb(e):
|
||||
slider = e.get_target()
|
||||
v = slider.get_value()
|
||||
# Notify all subscribers (only the label now) that the slider value has been changed
|
||||
lv.msg_send(MSG_NEW_TEMPERATURE, Temperature(v))
|
||||
|
||||
def label_event_cb(e):
|
||||
label = e.get_target()
|
||||
msg = e.get_msg()
|
||||
# Respond only to MSG_NEW_TEMPERATURE message
|
||||
if msg.get_id() == MSG_NEW_TEMPERATURE:
|
||||
payload = msg.get_payload()
|
||||
temprature = payload.__cast__()
|
||||
label.set_text(str(temprature))
|
||||
|
||||
# Create a slider in the center of the display
|
||||
slider = lv.slider(lv.scr_act())
|
||||
slider.center()
|
||||
slider.add_event_cb(slider_event_cb, lv.EVENT.VALUE_CHANGED, None)
|
||||
|
||||
# Create a label below the slider
|
||||
label = lv.label(lv.scr_act())
|
||||
label.add_event_cb(label_event_cb, lv.EVENT.MSG_RECEIVED, None)
|
||||
label.set_text("0%")
|
||||
label.align(lv.ALIGN.CENTER, 0, 30)
|
||||
|
||||
# Subscribe the label to a message
|
||||
lv.msg_subscribe_obj(MSG_NEW_TEMPERATURE, label, None)
|
||||
@@ -7,7 +7,7 @@
|
||||
#define MSG_LOGIN_ERROR 3
|
||||
#define MSG_LOGIN_OK 4
|
||||
|
||||
static void auth_manager(void * s, lv_msg_t * m);
|
||||
static void auth_manager(lv_msg_t * m);
|
||||
static void textarea_event_cb(lv_event_t * e);
|
||||
static void log_out_event_cb(lv_event_t * e);
|
||||
static void start_engine_msg_event_cb(lv_event_t * e);
|
||||
@@ -19,7 +19,7 @@ static void info_label_msg_event_cb(lv_event_t * e);
|
||||
*/
|
||||
void lv_example_msg_2(void)
|
||||
{
|
||||
lv_msg_subsribe(MSG_LOGIN_ATTEMPT, auth_manager, "hello");
|
||||
lv_msg_subscribe(MSG_LOGIN_ATTEMPT, auth_manager, "hello");
|
||||
|
||||
/*Create a slider in the center of the display*/
|
||||
lv_obj_t * ta = lv_textarea_create(lv_scr_act());
|
||||
@@ -29,9 +29,9 @@ void lv_example_msg_2(void)
|
||||
lv_textarea_set_password_mode(ta, true);
|
||||
lv_textarea_set_placeholder_text(ta, "The password is: hello");
|
||||
lv_obj_add_event_cb(ta, textarea_event_cb, LV_EVENT_ALL, NULL);
|
||||
lv_msg_subsribe_obj(MSG_LOGIN_ERROR, ta, NULL);
|
||||
lv_msg_subsribe_obj(MSG_LOGIN_OK, ta, NULL);
|
||||
lv_msg_subsribe_obj(MSG_LOG_OUT, ta, NULL);
|
||||
lv_msg_subscribe_obj(MSG_LOGIN_ERROR, ta, NULL);
|
||||
lv_msg_subscribe_obj(MSG_LOGIN_OK, ta, NULL);
|
||||
lv_msg_subscribe_obj(MSG_LOG_OUT, ta, NULL);
|
||||
|
||||
lv_obj_t * kb = lv_keyboard_create(lv_scr_act());
|
||||
lv_keyboard_set_textarea(kb, ta);
|
||||
@@ -43,8 +43,8 @@ void lv_example_msg_2(void)
|
||||
btn = lv_btn_create(lv_scr_act());
|
||||
lv_obj_set_pos(btn, 240, 10);
|
||||
lv_obj_add_event_cb(btn, log_out_event_cb, LV_EVENT_ALL, NULL);
|
||||
lv_msg_subsribe_obj(MSG_LOGIN_OK, btn, NULL);
|
||||
lv_msg_subsribe_obj(MSG_LOG_OUT, btn, NULL);
|
||||
lv_msg_subscribe_obj(MSG_LOGIN_OK, btn, NULL);
|
||||
lv_msg_subscribe_obj(MSG_LOG_OUT, btn, NULL);
|
||||
|
||||
label = lv_label_create(btn);
|
||||
lv_label_set_text(label, "LOG OUT");
|
||||
@@ -54,17 +54,17 @@ void lv_example_msg_2(void)
|
||||
lv_label_set_text(label, "");
|
||||
lv_obj_add_event_cb(label, info_label_msg_event_cb, LV_EVENT_MSG_RECEIVED, NULL);
|
||||
lv_obj_set_pos(label, 10, 60);
|
||||
lv_msg_subsribe_obj(MSG_LOGIN_ERROR, label, NULL);
|
||||
lv_msg_subsribe_obj(MSG_LOGIN_OK, label, NULL);
|
||||
lv_msg_subsribe_obj(MSG_LOG_OUT, label, NULL);
|
||||
lv_msg_subscribe_obj(MSG_LOGIN_ERROR, label, NULL);
|
||||
lv_msg_subscribe_obj(MSG_LOGIN_OK, label, NULL);
|
||||
lv_msg_subscribe_obj(MSG_LOG_OUT, label, NULL);
|
||||
|
||||
/*Create button which will be active only when logged in*/
|
||||
btn = lv_btn_create(lv_scr_act());
|
||||
lv_obj_set_pos(btn, 10, 80);
|
||||
lv_obj_add_event_cb(btn, start_engine_msg_event_cb, LV_EVENT_MSG_RECEIVED, NULL);
|
||||
lv_obj_add_flag(btn, LV_OBJ_FLAG_CHECKABLE);
|
||||
lv_msg_subsribe_obj(MSG_LOGIN_OK, btn, NULL);
|
||||
lv_msg_subsribe_obj(MSG_LOG_OUT, btn, NULL);
|
||||
lv_msg_subscribe_obj(MSG_LOGIN_OK, btn, NULL);
|
||||
lv_msg_subscribe_obj(MSG_LOG_OUT, btn, NULL);
|
||||
|
||||
label = lv_label_create(btn);
|
||||
lv_label_set_text(label, "START ENGINE");
|
||||
@@ -72,9 +72,8 @@ void lv_example_msg_2(void)
|
||||
lv_msg_send(MSG_LOG_OUT, NULL);
|
||||
}
|
||||
|
||||
static void auth_manager(void * s, lv_msg_t * m)
|
||||
static void auth_manager(lv_msg_t * m)
|
||||
{
|
||||
LV_UNUSED(s);
|
||||
const char * pin_act = lv_msg_get_payload(m);
|
||||
const char * pin_expexted = lv_msg_get_user_data(m);
|
||||
if(strcmp(pin_act, pin_expexted) == 0) {
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
#define MSG_UPDATE 4
|
||||
#define MSG_UPDATE_REQUEST 5
|
||||
|
||||
static void value_handler(void * s, lv_msg_t * m);
|
||||
static void value_handler(void * s, lv_msg_t * m);
|
||||
static void value_handler(lv_msg_t * m);
|
||||
static void btn_event_cb(lv_event_t * e);
|
||||
static void label_event_cb(lv_event_t * e);
|
||||
static void slider_event_cb(lv_event_t * e);
|
||||
@@ -23,11 +22,11 @@ static void slider_event_cb(lv_event_t * e);
|
||||
void lv_example_msg_3(void)
|
||||
{
|
||||
|
||||
lv_msg_subsribe(MSG_INC, value_handler, NULL);
|
||||
lv_msg_subsribe(MSG_DEC, value_handler, NULL);
|
||||
lv_msg_subsribe(MSG_SET, value_handler, NULL);
|
||||
lv_msg_subsribe(MSG_UPDATE, value_handler, NULL);
|
||||
lv_msg_subsribe(MSG_UPDATE_REQUEST, value_handler, NULL);
|
||||
lv_msg_subscribe(MSG_INC, value_handler, NULL);
|
||||
lv_msg_subscribe(MSG_DEC, value_handler, NULL);
|
||||
lv_msg_subscribe(MSG_SET, value_handler, NULL);
|
||||
lv_msg_subscribe(MSG_UPDATE, value_handler, NULL);
|
||||
lv_msg_subscribe(MSG_UPDATE_REQUEST, value_handler, NULL);
|
||||
|
||||
lv_obj_t * panel = lv_obj_create(lv_scr_act());
|
||||
lv_obj_set_size(panel, 250, LV_SIZE_CONTENT);
|
||||
@@ -51,7 +50,7 @@ void lv_example_msg_3(void)
|
||||
lv_obj_set_flex_grow(label, 2);
|
||||
lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, 0);
|
||||
lv_label_set_text(label, "?");
|
||||
lv_msg_subsribe_obj(MSG_UPDATE, label, NULL);
|
||||
lv_msg_subscribe_obj(MSG_UPDATE, label, NULL);
|
||||
lv_obj_add_event_cb(label, label_event_cb, LV_EVENT_MSG_RECEIVED, NULL);
|
||||
|
||||
/*Down button*/
|
||||
@@ -67,7 +66,7 @@ void lv_example_msg_3(void)
|
||||
lv_obj_set_flex_grow(slider, 1);
|
||||
lv_obj_add_flag(slider, LV_OBJ_FLAG_FLEX_IN_NEW_TRACK);
|
||||
lv_obj_add_event_cb(slider, slider_event_cb, LV_EVENT_ALL, NULL);
|
||||
lv_msg_subsribe_obj(MSG_UPDATE, slider, NULL);
|
||||
lv_msg_subscribe_obj(MSG_UPDATE, slider, NULL);
|
||||
|
||||
|
||||
/* As there are new UI elements that don't know the system's state
|
||||
@@ -76,10 +75,8 @@ void lv_example_msg_3(void)
|
||||
}
|
||||
|
||||
|
||||
static void value_handler(void * s, lv_msg_t * m)
|
||||
static void value_handler(lv_msg_t * m)
|
||||
{
|
||||
LV_UNUSED(s);
|
||||
|
||||
static int32_t value = 10;
|
||||
int32_t old_value = value;
|
||||
switch(lv_msg_get_id(m)) {
|
||||
|
||||
@@ -84,6 +84,13 @@ typedef enum {
|
||||
LV_EVENT_LAYOUT_CHANGED, /**< The children position has changed due to a layout recalculation*/
|
||||
LV_EVENT_GET_SELF_SIZE, /**< Get the internal size of a widget*/
|
||||
|
||||
/** Events of optional LVGL components*/
|
||||
#if LV_USE_MSG
|
||||
|
||||
LV_EVENT_MSG_RECEIVED,
|
||||
|
||||
#endif // LV_USE_MSG
|
||||
|
||||
_LV_EVENT_LAST, /** Number of default events*/
|
||||
|
||||
|
||||
|
||||
@@ -59,7 +59,8 @@ extern "C" {
|
||||
LV_DISPATCH(f, void * , _lv_theme_basic_styles) \
|
||||
LV_DISPATCH_COND(f, uint8_t *, _lv_font_decompr_buf, LV_USE_FONT_COMPRESSED, 1) \
|
||||
LV_DISPATCH(f, uint8_t * , _lv_grad_cache_mem) \
|
||||
LV_DISPATCH(f, uint8_t * , _lv_style_custom_prop_flag_lookup_table)
|
||||
LV_DISPATCH(f, uint8_t * , _lv_style_custom_prop_flag_lookup_table) \
|
||||
LV_DISPATCH(f, lv_ll_t, _subs_ll)
|
||||
|
||||
#define LV_DEFINE_ROOT(root_type, root_name) root_type root_name;
|
||||
#define LV_ROOTS LV_ITERATE_ROOTS(LV_DEFINE_ROOT)
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include "../../misc/lv_assert.h"
|
||||
#include "../../misc/lv_ll.h"
|
||||
#include "../../misc/lv_gc.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
@@ -32,18 +33,16 @@ typedef struct {
|
||||
**********************/
|
||||
|
||||
static void notify(lv_msg_t * m);
|
||||
static void obj_notify_cb(void * s, lv_msg_t * m);
|
||||
static void obj_notify_cb(lv_msg_t * m);
|
||||
static void obj_delete_event_cb(lv_event_t * e);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
static lv_ll_t subs_ll;
|
||||
|
||||
/**********************
|
||||
* GLOBAL VARIABLES
|
||||
**********************/
|
||||
lv_event_code_t LV_EVENT_MSG_RECEIVED;
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
@@ -55,13 +54,12 @@ lv_event_code_t LV_EVENT_MSG_RECEIVED;
|
||||
|
||||
void lv_msg_init(void)
|
||||
{
|
||||
LV_EVENT_MSG_RECEIVED = lv_event_register_id();
|
||||
_lv_ll_init(&subs_ll, sizeof(sub_dsc_t));
|
||||
_lv_ll_init(&LV_GC_ROOT(_subs_ll), sizeof(sub_dsc_t));
|
||||
}
|
||||
|
||||
void * lv_msg_subsribe(uint32_t msg_id, lv_msg_subscribe_cb_t cb, void * user_data)
|
||||
void * lv_msg_subscribe(uint32_t msg_id, lv_msg_subscribe_cb_t cb, void * user_data)
|
||||
{
|
||||
sub_dsc_t * s = _lv_ll_ins_tail(&subs_ll);
|
||||
sub_dsc_t * s = _lv_ll_ins_tail(&LV_GC_ROOT(_subs_ll));
|
||||
LV_ASSERT_MALLOC(s);
|
||||
if(s == NULL) return NULL;
|
||||
|
||||
@@ -73,9 +71,9 @@ void * lv_msg_subsribe(uint32_t msg_id, lv_msg_subscribe_cb_t cb, void * user_da
|
||||
return s;
|
||||
}
|
||||
|
||||
void * lv_msg_subsribe_obj(uint32_t msg_id, lv_obj_t * obj, void * user_data)
|
||||
void * lv_msg_subscribe_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);
|
||||
sub_dsc_t * s = lv_msg_subscribe(msg_id, obj_notify_cb, user_data);
|
||||
if(s == NULL) return NULL;
|
||||
s->_priv_data = obj;
|
||||
|
||||
@@ -90,7 +88,7 @@ void * lv_msg_subsribe_obj(uint32_t msg_id, lv_obj_t * obj, void * user_data)
|
||||
void lv_msg_unsubscribe(void * s)
|
||||
{
|
||||
LV_ASSERT_NULL(s);
|
||||
_lv_ll_remove(&subs_ll, s);
|
||||
_lv_ll_remove(&LV_GC_ROOT(_subs_ll), s);
|
||||
lv_free(s);
|
||||
}
|
||||
|
||||
@@ -138,18 +136,17 @@ lv_msg_t * lv_event_get_msg(lv_event_t * e)
|
||||
static void notify(lv_msg_t * m)
|
||||
{
|
||||
sub_dsc_t * s;
|
||||
_LV_LL_READ(&subs_ll, s) {
|
||||
_LV_LL_READ(&LV_GC_ROOT(_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);
|
||||
s->callback(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void obj_notify_cb(void * s, lv_msg_t * m)
|
||||
static void obj_notify_cb(lv_msg_t * m)
|
||||
{
|
||||
LV_UNUSED(s);
|
||||
lv_event_send(m->_priv_data, LV_EVENT_MSG_RECEIVED, m);
|
||||
}
|
||||
|
||||
@@ -157,11 +154,11 @@ 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 = _lv_ll_get_head(&LV_GC_ROOT(_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);
|
||||
s_next = _lv_ll_get_next(&LV_GC_ROOT(_subs_ll), s);
|
||||
if(s->_priv_data == obj) {
|
||||
lv_msg_unsubscribe(s);
|
||||
}
|
||||
|
||||
@@ -31,9 +31,8 @@ typedef struct {
|
||||
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);
|
||||
typedef void (*lv_msg_subscribe_cb_t)(lv_msg_t * msg);
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
@@ -51,7 +50,7 @@ void lv_msg_init(void);
|
||||
* @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);
|
||||
void * lv_msg_subscribe(uint32_t msg_id, lv_msg_subscribe_cb_t cb, void * user_data);
|
||||
|
||||
/**
|
||||
* Subscribe an `lv_obj` to a message.
|
||||
@@ -61,12 +60,12 @@ void * lv_msg_subsribe(uint32_t msg_id, lv_msg_subscribe_cb_t cb, void * user_da
|
||||
* @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);
|
||||
void * lv_msg_subscribe_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`
|
||||
* Return value of `lv_msg_subscribe` or `lv_msg_subscribe_obj`
|
||||
*/
|
||||
void lv_msg_unsubscribe(void * s);
|
||||
|
||||
@@ -109,8 +108,6 @@ lv_msg_t * lv_event_get_msg(lv_event_t * e);
|
||||
* GLOBAL VARIABLES
|
||||
**********************/
|
||||
|
||||
extern lv_event_code_t LV_EVENT_MSG_RECEIVED;
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
Reference in New Issue
Block a user