diff --git a/docs/others/msg.md b/docs/others/msg.md index 1238243c4..e0e886906 100644 --- a/docs/others/msg.md +++ b/docs/others/msg.md @@ -4,7 +4,7 @@ Messaging (`lv_msg`) is a classic [publisher subscriber](https://en.wikipedia.or ## IDs Both the publishers and the subscribers needs to know the message identifiers. -In `lv_msg` these are simple `uint32_t` integers. For example: +In `lv_msg` these are simple integers. For example: ```c #define MSG_DOOR_OPENED 1 #define MSG_DOOR_CLOSED 2 @@ -12,30 +12,38 @@ In `lv_msg` these are simple `uint32_t` integers. For example: #define MSG_USER_AVATAR_CHANGED 101 ``` -You can orgnaize the message IDs as you wish. +You can organize the message IDs as you wish. -Both parties also need to know about the format of teh payload. E.g. in the above example -`MSG_DOOR_OPENED` and `MSG_DOOR_CLOSED` has no payload but `MSG_USER_NAME_CHANGED` can have a `const char *` payload containing the user name, and `MSG_USER_AVATAR_CHANGED` a `const void *` image source with the new avatar image. +Both parties also need to know about the format of the payload. E.g. in the above example +`MSG_DOOR_OPENED` and `MSG_DOOR_CLOSED` might have no payload but `MSG_USER_NAME_CHANGED` can have a `const char *` payload containing the user name, and `MSG_USER_AVATAR_CHANGED` a `const void *` image source with the new avatar image. - -## Send message - -Messages can be sent with `lv_msg_send(msg_id, payload)`. E.g. +To be more precise the message ID`s type is declared like this: ```c -lv_msg_send(MSG_USER_DOOR_OPENED, NULL); -lv_msg_send(MSG_USER_NAME_CHANGED, "John Smith"); +typedef lv_uintptr_t lv_msg_id_t; ``` +This way, if you a value in stored in a global variable (e.g. the current temperature) then the address of that variable can be used as message ID too by simply casting it to `lv_msg_id_t`. It saves the creation of message IDs manually as the variable itself serves as message ID too. + + ## Subscribe to a message `lv_msg_subscribe(msg_id, callback, user_data)` can be used to subscribe to message. + +Don't forget that `msg_id` can be a constant or a variable address too: +```c +lv_msg_subscribe(45, my_callback_1, NULL); + +int v; +lv_msg_subscribe((lv_msg_id_t)&v, my_callback_2, NULL); +``` + The callback should look like this: ```c static void user_name_subscriber_cb(lv_msg_t * m) { - /*m: a message object with the msg_id, payload, and user_data (set durung subscription)*/ + /*m: a message object with the msg_id, payload, and user_data (set during subscription)*/ ...do something... } @@ -67,6 +75,12 @@ void user_name_label_event_cb(lv_event_t * e) ``` +Here `msg_id` also can be a variable's address: +```c +char name[64]; +lv_msg_subsribe_obj(name, user_name_label, NULL); +``` + ### Unsubscribe `lv_msg_subscribe` returns a pointer which can be used to unsubscribe: ```c @@ -78,6 +92,16 @@ s1 = lv_msg_subscribe(MSG_USER_DOOR_OPENED, some_callback, NULL); lv_msg_unsubscribe(s1); ``` +## Send message + +Messages can be sent with `lv_msg_send(msg_id, payload)`. E.g. +```c +lv_msg_send(MSG_USER_DOOR_OPENED, NULL); +lv_msg_send(MSG_USER_NAME_CHANGED, "John Smith"); +``` + +To update a variable + ## Example ```eval_rst diff --git a/examples/others/msg/lv_example_msg_3.c b/examples/others/msg/lv_example_msg_3.c index 545cc7b5d..7fa93caf4 100644 --- a/examples/others/msg/lv_example_msg_3.c +++ b/examples/others/msg/lv_example_msg_3.c @@ -1,18 +1,13 @@ #include "../../lv_examples.h" #if LV_USE_MSG && LV_USE_SLIDER && LV_USE_LABEL && LV_BUILD_EXAMPLES -/*Define a message ID*/ -#define MSG_INC 1 -#define MSG_DEC 2 -#define MSG_SET 3 -#define MSG_UPDATE 4 -#define MSG_UPDATE_REQUEST 5 - -static void value_handler(lv_msg_t * m); +static int32_t limit_value(int32_t v); 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); +static int32_t power_value; + /** * Show how an increment button, a decrement button, as slider can set a value * and a label display it. @@ -22,12 +17,6 @@ static void slider_event_cb(lv_event_t * e); void lv_example_msg_3(void) { - 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); lv_obj_center(panel); @@ -50,7 +39,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_subscribe_obj(MSG_UPDATE, label, NULL); + lv_msg_subscribe_obj((lv_msg_id_t)&power_value, label, NULL); lv_obj_add_event_cb(label, label_event_cb, LV_EVENT_MSG_RECEIVED, NULL); /*Down button*/ @@ -65,42 +54,16 @@ void lv_example_msg_3(void) lv_obj_t * slider = lv_slider_create(panel); lv_obj_set_flex_grow(slider, 1); lv_obj_add_flag(slider, LV_OBJ_FLAG_FLEX_IN_NEW_TRACK); + lv_msg_subscribe_obj((lv_msg_id_t)&power_value, slider, NULL); lv_obj_add_event_cb(slider, slider_event_cb, LV_EVENT_ALL, NULL); - lv_msg_subscribe_obj(MSG_UPDATE, slider, NULL); - - /* As there are new UI elements that don't know the system's state - * send an UPDATE REQUEST message which will trigger an UPDATE message with the current value*/ - lv_msg_send(MSG_UPDATE_REQUEST, NULL); + power_value = 30; + lv_msg_update_value(&power_value); } - -static void value_handler(lv_msg_t * m) +static int32_t limit_value(int32_t v) { - static int32_t value = 10; - int32_t old_value = value; - switch(lv_msg_get_id(m)) { - case MSG_INC: - if(value < 100) value++; - break; - case MSG_DEC: - if(value > 0) value--; - break; - case MSG_SET: { - const int32_t * new_value = lv_msg_get_payload(m); - value = *new_value; - } - break; - case MSG_UPDATE_REQUEST: - lv_msg_send(MSG_UPDATE, &value); - break; - default: - break; - } - - if(value != old_value) { - lv_msg_send(MSG_UPDATE, &value); - } + return LV_CLAMP(30, v, 80); } @@ -110,10 +73,12 @@ static void btn_event_cb(lv_event_t * e) lv_event_code_t code = lv_event_get_code(e); if(code == LV_EVENT_CLICKED || code == LV_EVENT_LONG_PRESSED_REPEAT) { if(lv_obj_get_index(btn) == 0) { /*First object is the dec. button*/ - lv_msg_send(MSG_DEC, NULL); + power_value = limit_value(power_value - 1); + lv_msg_update_value(&power_value); } else { - lv_msg_send(MSG_INC, NULL); + power_value = limit_value(power_value + 1); + lv_msg_update_value(&power_value); } } } @@ -124,10 +89,8 @@ static void label_event_cb(lv_event_t * e) lv_event_code_t code = lv_event_get_code(e); if(code == LV_EVENT_MSG_RECEIVED) { lv_msg_t * m = lv_event_get_msg(e); - if(lv_msg_get_id(m) == MSG_UPDATE) { - const int32_t * v = lv_msg_get_payload(m); - lv_label_set_text_fmt(label, "%d %%", *v); - } + const int32_t * v = lv_msg_get_payload(m); + lv_label_set_text_fmt(label, "%d %%", *v); } } @@ -136,15 +99,13 @@ static void slider_event_cb(lv_event_t * e) lv_obj_t * slider = lv_event_get_target(e); lv_event_code_t code = lv_event_get_code(e); if(code == LV_EVENT_VALUE_CHANGED) { - int32_t v = lv_slider_get_value(slider); - lv_msg_send(MSG_SET, &v); + power_value = limit_value(lv_slider_get_value(slider)); + lv_msg_update_value(&power_value); } else if(code == LV_EVENT_MSG_RECEIVED) { lv_msg_t * m = lv_event_get_msg(e); - if(lv_msg_get_id(m) == MSG_UPDATE) { - const int32_t * v = lv_msg_get_payload(m); - lv_slider_set_value(slider, *v, LV_ANIM_OFF); - } + const int32_t * v = lv_msg_get_payload(m); + lv_slider_set_value(slider, *v, LV_ANIM_OFF); } } diff --git a/src/core/lv_disp.c b/src/core/lv_disp.c index f19a5b831..9d675e7d3 100644 --- a/src/core/lv_disp.c +++ b/src/core/lv_disp.c @@ -232,7 +232,6 @@ lv_color_t lv_disp_get_chroma_key_color(lv_disp_t * disp) */ void lv_scr_load_anim(lv_obj_t * new_scr, lv_scr_load_anim_t anim_type, uint32_t time, uint32_t delay, bool auto_del) { - lv_disp_t * d = lv_obj_get_disp(new_scr); lv_obj_t * act_scr = lv_scr_act(); @@ -273,7 +272,9 @@ void lv_scr_load_anim(lv_obj_t * new_scr, lv_scr_load_anim_t anim_type, uint32_t /*Shortcut for immediate load*/ if(time == 0 && delay == 0) { + scr_load_internal(new_scr); + if(auto_del) lv_obj_del(act_scr); return; } diff --git a/src/lv_conf_internal.h b/src/lv_conf_internal.h index 0065d7afc..d6e8c7650 100644 --- a/src/lv_conf_internal.h +++ b/src/lv_conf_internal.h @@ -309,7 +309,7 @@ #if LV_USE_DRAW_SW /*Enable complex draw engine. - *Required to draw shadow, gradient, rounded corners, circles, arc, skew lines, image transformations or any masks*/ + *Required to draw shadow, gradient, rounded corners, circles, arc, skew lines, image transformations or any masks*/ #ifndef LV_DRAW_SW_COMPLEX #ifdef _LV_KCONFIG_PRESENT #ifdef CONFIG_LV_DRAW_SW_COMPLEX @@ -323,9 +323,9 @@ #endif /* If a widget has `style_opa < 255` (not `bg_opa`, `text_opa` etc) or not NORMAL blend mode - * it is buffered into a "simple" layer before rendering. The widget can be buffered in smaller chunks. - * "Transformed layers" (if `transform_angle/zoom` are set) use larger buffers - * and can't be drawn in chunks. */ + * it is buffered into a "simple" layer before rendering. The widget can be buffered in smaller chunks. + * "Transformed layers" (if `transform_angle/zoom` are set) use larger buffers + * and can't be drawn in chunks. */ /*The target buffer size for simple layer chunks.*/ #ifndef LV_DRAW_SW_LAYER_SIMPLE_BUF_SIZE @@ -369,10 +369,10 @@ #endif /*Default gradient buffer size. - *When LVGL calculates the gradient "maps" it can save them into a cache to avoid calculating them again. - *LV_DRAW_SW_GRADIENT_CACHE_DEF_SIZE sets the size of this cache in bytes. - *If the cache is too small the map will be allocated only while it's required for the drawing. - *0 mean no caching.*/ + *When LVGL calculates the gradient "maps" it can save them into a cache to avoid calculating them again. + *LV_DRAW_SW_GRADIENT_CACHE_DEF_SIZE sets the size of this cache in bytes. + *If the cache is too small the map will be allocated only while it's required for the drawing. + *0 mean no caching.*/ #ifndef LV_DRAW_SW_GRADIENT_CACHE_DEF_SIZE #ifdef CONFIG_LV_DRAW_SW_GRADIENT_CACHE_DEF_SIZE #define LV_DRAW_SW_GRADIENT_CACHE_DEF_SIZE CONFIG_LV_DRAW_SW_GRADIENT_CACHE_DEF_SIZE @@ -382,8 +382,8 @@ #endif /*Allow dithering the gradients (to achieve visual smooth color gradients on limited color depth display) - *LV_DRAW_SW_GRADIENT_DITHER implies allocating one or two more lines of the object's rendering surface - *The increase in memory consumption is (32 bits * object width) plus 24 bits * object width if using error diffusion */ + *LV_DRAW_SW_GRADIENT_DITHER implies allocating one or two more lines of the object's rendering surface + *The increase in memory consumption is (32 bits * object width) plus 24 bits * object width if using error diffusion */ #ifndef LV_DRAW_SW_GRADIENT_DITHER #ifdef CONFIG_LV_DRAW_SW_GRADIENT_DITHER #define LV_DRAW_SW_GRADIENT_DITHER CONFIG_LV_DRAW_SW_GRADIENT_DITHER @@ -393,8 +393,8 @@ #endif #if LV_DRAW_SW_GRADIENT_DITHER /*Add support for error diffusion dithering. - *Error diffusion dithering gets a much better visual result, but implies more CPU consumption and memory when drawing. - *The increase in memory consumption is (24 bits * object's width)*/ + *Error diffusion dithering gets a much better visual result, but implies more CPU consumption and memory when drawing. + *The increase in memory consumption is (24 bits * object's width)*/ #ifndef LV_DRAW_SW_GRADIENT_DITHER_ERROR_DIFFUSION #ifdef CONFIG_LV_DRAW_SW_GRADIENT_DITHER_ERROR_DIFFUSION #define LV_DRAW_SW_GRADIENT_DITHER_ERROR_DIFFUSION CONFIG_LV_DRAW_SW_GRADIENT_DITHER_ERROR_DIFFUSION @@ -585,7 +585,7 @@ #endif /*1: Enable print timestamp; - *0: Disable print timestamp*/ + *0: Disable print timestamp*/ #ifndef LV_LOG_USE_TIMESTAMP #ifdef _LV_KCONFIG_PRESENT #ifdef CONFIG_LV_LOG_USE_TIMESTAMP @@ -2269,6 +2269,16 @@ #endif #endif +/*1: Enable a database where values can be stored in a global place. + * Requires: lv_msg */ +#ifndef LV_USE_DB + #ifdef CONFIG_LV_USE_DB + #define LV_USE_DB CONFIG_LV_USE_DB + #else + #define LV_USE_DB 0 + #endif +#endif + /*1: Enable Pinyin input method*/ /*Requires: lv_keyboard*/ #ifndef LV_USE_IME_PINYIN diff --git a/src/others/msg/lv_msg.c b/src/others/msg/lv_msg.c index 16b0f0bf4..ed22f2f76 100644 --- a/src/others/msg/lv_msg.c +++ b/src/others/msg/lv_msg.c @@ -22,7 +22,7 @@ **********************/ typedef struct { - uint32_t msg_id; + lv_msg_id_t msg_id; lv_msg_subscribe_cb_t callback; void * user_data; void * _priv_data; /*Internal: used only store 'obj' in lv_obj_subscribe*/ @@ -57,7 +57,7 @@ void lv_msg_init(void) _lv_ll_init(&LV_GC_ROOT(_subs_ll), sizeof(sub_dsc_t)); } -void * lv_msg_subscribe(uint32_t msg_id, lv_msg_subscribe_cb_t cb, void * user_data) +void * lv_msg_subscribe(lv_msg_id_t msg_id, lv_msg_subscribe_cb_t cb, void * user_data) { sub_dsc_t * s = _lv_ll_ins_tail(&LV_GC_ROOT(_subs_ll)); LV_ASSERT_MALLOC(s); @@ -71,7 +71,7 @@ void * lv_msg_subscribe(uint32_t msg_id, lv_msg_subscribe_cb_t cb, void * user_d return s; } -void * lv_msg_subscribe_obj(uint32_t msg_id, lv_obj_t * obj, void * user_data) +void * lv_msg_subscribe_obj(lv_msg_id_t msg_id, lv_obj_t * obj, void * user_data) { sub_dsc_t * s = lv_msg_subscribe(msg_id, obj_notify_cb, user_data); if(s == NULL) return NULL; @@ -92,7 +92,7 @@ void lv_msg_unsubscribe(void * s) lv_free(s); } -void lv_msg_send(uint32_t msg_id, const void * payload) +void lv_msg_send(lv_msg_id_t msg_id, const void * payload) { lv_msg_t m; lv_memzero(&m, sizeof(m)); @@ -101,7 +101,12 @@ void lv_msg_send(uint32_t msg_id, const void * payload) notify(&m); } -uint32_t lv_msg_get_id(lv_msg_t * m) +void lv_msg_update_value(void * v) +{ + lv_msg_send((lv_msg_id_t)v, v); +} + +lv_msg_id_t lv_msg_get_id(lv_msg_t * m) { return m->id; } @@ -127,8 +132,6 @@ lv_msg_t * lv_event_get_msg(lv_event_t * e) } } - - /********************** * STATIC FUNCTIONS **********************/ diff --git a/src/others/msg/lv_msg.h b/src/others/msg/lv_msg.h index 53b6065ff..48204d928 100644 --- a/src/others/msg/lv_msg.h +++ b/src/others/msg/lv_msg.h @@ -24,8 +24,10 @@ extern "C" { * TYPEDEFS **********************/ +typedef lv_uintptr_t lv_msg_id_t; + typedef struct { - uint32_t id; /*Identifier of the message*/ + lv_msg_id_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*/ @@ -50,7 +52,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_subscribe(uint32_t msg_id, lv_msg_subscribe_cb_t cb, void * user_data); +void * lv_msg_subscribe(lv_msg_id_t msg_id, lv_msg_subscribe_cb_t cb, void * user_data); /** * Subscribe an `lv_obj` to a message. @@ -60,7 +62,7 @@ void * lv_msg_subscribe(uint32_t msg_id, lv_msg_subscribe_cb_t cb, void * user_d * @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_subscribe_obj(uint32_t msg_id, lv_obj_t * obj, void * user_data); +void * lv_msg_subscribe_obj(lv_msg_id_t msg_id, lv_obj_t * obj, void * user_data); /** * Cancel a previous subscription @@ -74,14 +76,24 @@ void lv_msg_unsubscribe(void * s); * @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); +void lv_msg_send(lv_msg_id_t msg_id, const void * payload); + +/** + * Send a message where the message ID is `v` (the value of the pointer) + * and the payload is `v`. + * It can be used to send unique messages when a variable changed. + * @param v pointer to a variable. + * @note to subscribe to a variable use `lv_msg_subscribe((lv_msg_id_t)v, msg_cb, user_data)` + * or `lv_msg_subscribe_obj((lv_msg_id_t)v, obj, user_data)` + */ +void lv_msg_update_value(void * v); /** * 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); +lv_msg_id_t lv_msg_get_id(lv_msg_t * m); /** * Get the payload of a message object. Typically used in the subscriber callback. diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index cedaa225f..a23384c9a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -41,6 +41,7 @@ set(LVGL_TEST_OPTIONS_MINIMAL_MONOCHROME -DLV_USE_BMP=1 -DLV_USE_GIF=1 -DLV_USE_QRCODE=1 + -DLV_USE_MSG=1 ) set(LVGL_TEST_OPTIONS_NORMAL_8BIT @@ -66,6 +67,7 @@ set(LVGL_TEST_OPTIONS_NORMAL_8BIT -DLV_USE_SJPG=1 -DLV_USE_GIF=1 -DLV_USE_QRCODE=1 + -DLV_USE_MSG=1 ) set(LVGL_TEST_OPTIONS_16BIT @@ -92,6 +94,7 @@ set(LVGL_TEST_OPTIONS_16BIT -DLV_USE_SJPG=1 -DLV_USE_GIF=1 -DLV_USE_QRCODE=1 + -DLV_USE_MSG=1 ) set(LVGL_TEST_OPTIONS_16BIT_SWAP @@ -120,6 +123,7 @@ set(LVGL_TEST_OPTIONS_16BIT_SWAP -DLV_USE_SJPG=1 -DLV_USE_GIF=1 -DLV_USE_QRCODE=1 + -DLV_USE_MSG=1 ) set(LVGL_TEST_OPTIONS_FULL_32BIT @@ -189,8 +193,8 @@ set(LVGL_TEST_OPTIONS_FULL_32BIT -DLV_USE_QRCODE=1 -DLV_USE_FRAGMENT=1 -DLV_USE_IMGFONT=1 - -DLV_USE_MSG=1 -DLV_USE_IME_PINYIN=1 + -DLV_USE_MSG=1 ) set(LVGL_TEST_OPTIONS_TEST_COMMON @@ -235,6 +239,7 @@ set(LVGL_TEST_OPTIONS_TEST_COMMON -DLV_USE_FS_POSIX=1 -DLV_FS_POSIX_LETTER='B' -DLV_FS_POSIX_CACHE_SIZE=0 + -DLV_USE_MSG=1 ${LVGL_TEST_COMMON_EXAMPLE_OPTIONS} -DLV_FONT_DEFAULT=&lv_font_montserrat_14 -Wno-unused-but-set-variable # unused variables are common in the dual-heap arrangement diff --git a/tests/src/test_cases/test_msg.c b/tests/src/test_cases/test_msg.c new file mode 100644 index 000000000..1e18568d8 --- /dev/null +++ b/tests/src/test_cases/test_msg.c @@ -0,0 +1,55 @@ +#if LV_BUILD_TEST +#include "../lvgl.h" + +#include "unity/unity.h" + +void setUp(void) +{ + /* Function run before every test */ +} + +void tearDown(void) +{ + /* Function run after every test */ +} + + +static uint32_t value_received; + +static void msg_cb(lv_msg_t * msg) +{ + uint32_t * v = lv_msg_get_payload(msg); + value_received = *v; +} +static void event_cb(lv_event_t * e) +{ + lv_msg_t * msg = lv_event_get_msg(e); + uint32_t * v = lv_msg_get_payload(msg); + lv_label_set_text_fmt(lv_event_get_target(e), "%d", *v); +} + +void test_add_entry_and_send_msg(void) +{ + static uint32_t value = 100; + lv_msg_subscribe((lv_msg_id_t)&value, msg_cb, NULL); + + value_received = 0; + value = 100; + lv_msg_update_value(&value); + TEST_ASSERT_EQUAL_UINT32(100, value_received); + + value = 200; + lv_msg_update_value(&value); + TEST_ASSERT_EQUAL_UINT32(200, value_received); + + lv_obj_t * label = lv_label_create(lv_scr_act()); + lv_msg_subscribe_obj((lv_msg_id_t)&value, label, NULL); + lv_obj_add_event_cb(label, event_cb, LV_EVENT_MSG_RECEIVED, NULL); + + value = 300; + lv_msg_update_value(&value); + TEST_ASSERT_EQUAL_STRING("300", lv_label_get_text(label)); +} + + +#endif