From cd114765927a4789897ec58ca96345bfeba079ad Mon Sep 17 00:00:00 2001 From: Amir Gonnen Date: Wed, 27 Jul 2022 10:42:48 +0300 Subject: [PATCH] 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 --- docs/others/msg.md | 5 ++-- examples/others/msg/lv_example_msg_1.c | 2 +- examples/others/msg/lv_example_msg_1.py | 39 +++++++++++++++++++++++++ examples/others/msg/lv_example_msg_2.c | 27 +++++++++-------- examples/others/msg/lv_example_msg_3.c | 21 ++++++------- src/core/lv_event.h | 7 +++++ src/misc/lv_gc.h | 5 ++-- src/others/msg/lv_msg.c | 29 +++++++++--------- src/others/msg/lv_msg.h | 11 +++---- 9 files changed, 91 insertions(+), 55 deletions(-) create mode 100644 examples/others/msg/lv_example_msg_1.py diff --git a/docs/others/msg.md b/docs/others/msg.md index 53deb5822..1238243c4 100644 --- a/docs/others/msg.md +++ b/docs/others/msg.md @@ -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... diff --git a/examples/others/msg/lv_example_msg_1.c b/examples/others/msg/lv_example_msg_1.c index d2cb8a3df..8f9aa7618 100644 --- a/examples/others/msg/lv_example_msg_1.c +++ b/examples/others/msg/lv_example_msg_1.c @@ -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) diff --git a/examples/others/msg/lv_example_msg_1.py b/examples/others/msg/lv_example_msg_1.py new file mode 100644 index 000000000..b8a0f2e36 --- /dev/null +++ b/examples/others/msg/lv_example_msg_1.py @@ -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) diff --git a/examples/others/msg/lv_example_msg_2.c b/examples/others/msg/lv_example_msg_2.c index f9cf585eb..573af82ff 100644 --- a/examples/others/msg/lv_example_msg_2.c +++ b/examples/others/msg/lv_example_msg_2.c @@ -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) { diff --git a/examples/others/msg/lv_example_msg_3.c b/examples/others/msg/lv_example_msg_3.c index dddb4a8c4..545cc7b5d 100644 --- a/examples/others/msg/lv_example_msg_3.c +++ b/examples/others/msg/lv_example_msg_3.c @@ -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)) { diff --git a/src/core/lv_event.h b/src/core/lv_event.h index d5a9eb6ba..c0082d204 100644 --- a/src/core/lv_event.h +++ b/src/core/lv_event.h @@ -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*/ diff --git a/src/misc/lv_gc.h b/src/misc/lv_gc.h index cbabb4a8c..55cf920c0 100644 --- a/src/misc/lv_gc.h +++ b/src/misc/lv_gc.h @@ -56,10 +56,11 @@ extern "C" { LV_DISPATCH_COND(f, _lv_draw_mask_radius_circle_dsc_arr_t , _lv_circle_cache, LV_USE_DRAW_MASKS, 1) \ LV_DISPATCH_COND(f, _lv_draw_mask_saved_arr_t , _lv_draw_mask_list, LV_USE_DRAW_MASKS, 1) \ LV_DISPATCH(f, void * , _lv_theme_default_styles) \ - LV_DISPATCH(f, void * , _lv_theme_basic_styles) \ + 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) diff --git a/src/others/msg/lv_msg.c b/src/others/msg/lv_msg.c index af16f0caf..16b0f0bf4 100644 --- a/src/others/msg/lv_msg.c +++ b/src/others/msg/lv_msg.c @@ -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); } diff --git a/src/others/msg/lv_msg.h b/src/others/msg/lv_msg.h index 834553632..53b6065ff 100644 --- a/src/others/msg/lv_msg.h +++ b/src/others/msg/lv_msg.h @@ -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 **********************/