From 22a143f44234fa6234401d412a97afc453dbb3df Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Mon, 13 May 2024 19:05:12 +0200 Subject: [PATCH] fix(sysmon): fix MicroPython compilation error when system monitor is enabled (#6073) Co-authored-by: Gabor Peresztegi Co-authored-by: Neo Xu --- scripts/lv_conf_internal_gen.py | 5 + src/core/lv_global.h | 4 +- src/core/lv_refr.c | 2 +- src/display/lv_display.c | 9 ++ src/display/lv_display_private.h | 15 +++ src/lv_conf_internal.h | 5 + src/misc/lv_types.h | 12 ++ src/others/observer/lv_observer.c | 22 ++++ src/others/observer/lv_observer.h | 9 ++ src/others/sysmon/lv_sysmon.c | 164 +++++++++++++++++---------- src/others/sysmon/lv_sysmon.h | 50 +++++--- tests/src/lv_test_conf.h | 2 - tests/src/lv_test_conf_full.h | 2 + tests/src/lv_test_init.c | 8 ++ tests/src/test_cases/test_observer.c | 22 ++++ 15 files changed, 255 insertions(+), 76 deletions(-) diff --git a/scripts/lv_conf_internal_gen.py b/scripts/lv_conf_internal_gen.py index 2b97452dbe..0242d35680 100755 --- a/scripts/lv_conf_internal_gen.py +++ b/scripts/lv_conf_internal_gen.py @@ -190,6 +190,11 @@ LV_EXPORT_CONST_INT(LV_DRAW_BUF_ALIGN); #define LV_LOG_TRACE_ANIM 0 #endif /*LV_USE_LOG*/ +#if LV_USE_SYSMON == 0 + #define LV_USE_PERF_MONITOR 0 + #define LV_USE_MEM_MONITOR 0 +#endif /*LV_USE_SYSMON*/ + #ifndef LV_USE_LZ4 #define LV_USE_LZ4 (LV_USE_LZ4_INTERNAL || LV_USE_LZ4_EXTERNAL) #endif diff --git a/src/core/lv_global.h b/src/core/lv_global.h index 8436eca05b..050fc8c825 100644 --- a/src/core/lv_global.h +++ b/src/core/lv_global.h @@ -193,11 +193,11 @@ typedef struct _lv_global_t { lv_style_t fe_list_button_style; #endif -#if LV_USE_SYSMON && LV_USE_PERF_MONITOR +#if LV_USE_PERF_MONITOR lv_sysmon_backend_data_t sysmon_perf; #endif -#if LV_USE_SYSMON && LV_USE_MEM_MONITOR +#if LV_USE_MEM_MONITOR lv_sysmon_backend_data_t sysmon_mem; #endif diff --git a/src/core/lv_refr.c b/src/core/lv_refr.c index 2a1a7441fb..cc97dbd0c6 100644 --- a/src/core/lv_refr.c +++ b/src/core/lv_refr.c @@ -331,7 +331,7 @@ void _lv_display_refr_timer(lv_timer_t * tmr) /* Ensure the timer does not run again automatically. * This is done before refreshing in case refreshing invalidates something else. * However if the performance monitor is enabled keep the timer running to count the FPS.*/ -#if !(defined(LV_USE_PERF_MONITOR) && LV_USE_PERF_MONITOR) +#if LV_USE_PERF_MONITOR lv_timer_pause(tmr); #endif } diff --git a/src/display/lv_display.c b/src/display/lv_display.c index deb308a63e..81fe6c9ac7 100644 --- a/src/display/lv_display.c +++ b/src/display/lv_display.c @@ -13,6 +13,7 @@ #include "../stdlib/lv_string.h" #include "../themes/lv_theme.h" #include "../core/lv_global.h" +#include "../others/sysmon/lv_sysmon.h" #if LV_USE_DRAW_SW #include "../draw/sw/lv_draw_sw.h" @@ -139,6 +140,14 @@ lv_display_t * lv_display_create(int32_t hor_res, int32_t ver_res) lv_timer_ready(disp->refr_timer); /*Be sure the screen will be refreshed immediately on start up*/ +#if LV_USE_PERF_MONITOR + lv_sysmon_show_performance(disp); +#endif + +#if LV_USE_MEM_MONITOR + lv_sysmon_show_memory(disp); +#endif + return disp; } diff --git a/src/display/lv_display_private.h b/src/display/lv_display_private.h index 155b9561c3..b9ea9c50c8 100644 --- a/src/display/lv_display_private.h +++ b/src/display/lv_display_private.h @@ -18,6 +18,10 @@ extern "C" { #include "../draw/lv_draw.h" #include "lv_display.h" +#if LV_USE_SYSMON +#include "../others/sysmon/lv_sysmon.h" +#endif + /********************* * DEFINES *********************/ @@ -148,6 +152,17 @@ struct _lv_display_t { /** The area being refreshed*/ lv_area_t refreshed_area; + +#if LV_USE_PERF_MONITOR + lv_obj_t * perf_label; + lv_sysmon_backend_data_t perf_sysmon_backend; + lv_sysmon_perf_info_t perf_sysmon_info; +#endif + +#if LV_USE_MEM_MONITOR + lv_obj_t * mem_label; +#endif + }; /********************** diff --git a/src/lv_conf_internal.h b/src/lv_conf_internal.h index 847825bea6..32ebee4547 100644 --- a/src/lv_conf_internal.h +++ b/src/lv_conf_internal.h @@ -3348,6 +3348,11 @@ LV_EXPORT_CONST_INT(LV_DRAW_BUF_ALIGN); #define LV_LOG_TRACE_ANIM 0 #endif /*LV_USE_LOG*/ +#if LV_USE_SYSMON == 0 + #define LV_USE_PERF_MONITOR 0 + #define LV_USE_MEM_MONITOR 0 +#endif /*LV_USE_SYSMON*/ + #ifndef LV_USE_LZ4 #define LV_USE_LZ4 (LV_USE_LZ4_INTERNAL || LV_USE_LZ4_EXTERNAL) #endif diff --git a/src/misc/lv_types.h b/src/misc/lv_types.h index 3bd3121bd7..ecded1fe43 100644 --- a/src/misc/lv_types.h +++ b/src/misc/lv_types.h @@ -148,6 +148,18 @@ typedef struct _lv_font_t lv_font_t; struct _lv_image_decoder_t; typedef struct _lv_image_decoder_t lv_image_decoder_t; +#if LV_USE_SYSMON + +struct _lv_sysmon_backend_data_t; +typedef struct _lv_sysmon_backend_data_t lv_sysmon_backend_data_t; + +#if LV_USE_PERF_MONITOR +struct _lv_sysmon_perf_info_t; +typedef struct _lv_sysmon_perf_info_t lv_sysmon_perf_info_t; +#endif /*LV_USE_PERF_MONITOR*/ + +#endif /*LV_USE_SYSMON*/ + #endif /*__ASSEMBLY__*/ /********************** diff --git a/src/others/observer/lv_observer.c b/src/others/observer/lv_observer.c index 4118759ade..0b6e94a36e 100644 --- a/src/others/observer/lv_observer.c +++ b/src/others/observer/lv_observer.c @@ -262,6 +262,24 @@ void lv_subject_init_group(lv_subject_t * subject, lv_subject_t * list[], uint32 } } +void lv_subject_deinit(lv_subject_t * subject) +{ + lv_observer_t * observer = _lv_ll_get_head(&subject->subs_ll); + while(observer) { + lv_observer_t * observer_next = _lv_ll_get_next(&subject->subs_ll, observer); + + if(observer->for_obj) { + lv_obj_remove_event_cb(observer->target, unsubscribe_on_delete_cb); + lv_obj_remove_event_cb_with_user_data(observer->target, NULL, subject); + } + + lv_observer_remove(observer); + observer = observer_next; + } + + _lv_ll_clear(&subject->subs_ll); +} + lv_subject_t * lv_subject_get_group_element(lv_subject_t * subject, int32_t index) { if(subject->type != LV_SUBJECT_TYPE_GROUP) { @@ -277,6 +295,9 @@ lv_subject_t * lv_subject_get_group_element(lv_subject_t * subject, int32_t inde lv_observer_t * lv_subject_add_observer(lv_subject_t * subject, lv_observer_cb_t cb, void * user_data) { lv_observer_t * observer = lv_subject_add_observer_obj(subject, cb, NULL, user_data); + if(observer == NULL) return NULL; + + observer->for_obj = 0; return observer; } @@ -298,6 +319,7 @@ lv_observer_t * lv_subject_add_observer_obj(lv_subject_t * subject, lv_observer_ observer->cb = cb; observer->user_data = user_data; observer->target = obj; + observer->for_obj = 1; /* subscribe to delete event of the object */ if(obj != NULL) { lv_obj_add_event_cb(obj, unsubscribe_on_delete_cb, LV_EVENT_DELETE, observer); diff --git a/src/others/observer/lv_observer.h b/src/others/observer/lv_observer.h index 25b67e716d..7ef19cb147 100644 --- a/src/others/observer/lv_observer.h +++ b/src/others/observer/lv_observer.h @@ -77,6 +77,7 @@ struct _lv_observer_t { void * user_data; /**< Additional parameter supplied when subscribing*/ uint32_t auto_free_user_data : 1; /**< Automatically free user data when the observer is removed */ uint32_t notified : 1; /**< Mark if this observer was already notified*/ + uint32_t for_obj : 1; /**< `target` is an `lv_obj_t *`*/ }; /********************** @@ -209,6 +210,14 @@ lv_color_t lv_subject_get_previous_color(lv_subject_t * subject); */ void lv_subject_init_group(lv_subject_t * subject, lv_subject_t * list[], uint32_t list_len); +/** + * Remove all the observers from a subject and free all allocated memories in it + * @param subject pointer to the subject + * @note objects added with `lv_subject_add_observer_obj` should be already deleted or + * removed manually. + */ +void lv_subject_deinit(lv_subject_t * subject); + /** * Get an element from the subject group's list * @param subject pointer to the subject diff --git a/src/others/sysmon/lv_sysmon.c b/src/others/sysmon/lv_sysmon.c index a9f311fbc1..b13a19fea6 100644 --- a/src/others/sysmon/lv_sysmon.c +++ b/src/others/sysmon/lv_sysmon.c @@ -15,26 +15,17 @@ #include "../../misc/lv_async.h" #include "../../stdlib/lv_string.h" #include "../../widgets/label/lv_label.h" +#include "../../display/lv_display_private.h" /********************* * DEFINES *********************/ -#define MY_CLASS (&lv_sysmon_class) - -#define SYSMON_REFR_PERIOD_DEF 300 /* ms */ - -#if defined(LV_USE_PERF_MONITOR) && LV_USE_PERF_MONITOR - #define sysmon_perf LV_GLOBAL_DEFAULT()->sysmon_perf - #define _USE_PERF_MONITOR 1 -#else - #define _USE_PERF_MONITOR 0 +#ifndef LV_SYSMON_REFR_PERIOD_DEF + #define LV_SYSMON_REFR_PERIOD_DEF 300 /* ms */ #endif -#if defined(LV_USE_MEM_MONITOR) && LV_USE_MEM_MONITOR +#if LV_USE_MEM_MONITOR #define sysmon_mem LV_GLOBAL_DEFAULT()->sysmon_mem - #define _USE_MEM_MONITOR 1 -#else - #define _USE_MEM_MONITOR 0 #endif /********************** @@ -45,12 +36,13 @@ * STATIC PROTOTYPES **********************/ -#if _USE_PERF_MONITOR +#if LV_USE_PERF_MONITOR static void perf_update_timer_cb(lv_timer_t * t); static void perf_observer_cb(lv_observer_t * observer, lv_subject_t * subject); + static void perf_monitor_disp_event_cb(lv_event_t * e); #endif -#if _USE_MEM_MONITOR +#if LV_USE_MEM_MONITOR static void mem_update_timer_cb(lv_timer_t * t); static void mem_observer_cb(lv_observer_t * observer, lv_subject_t * subject); #endif @@ -69,34 +61,31 @@ void _lv_sysmon_builtin_init(void) { -#if _USE_PERF_MONITOR - static lv_sysmon_perf_info_t perf_info; - lv_subject_init_pointer(&sysmon_perf.subject, &perf_info); - sysmon_perf.timer = lv_timer_create(perf_update_timer_cb, SYSMON_REFR_PERIOD_DEF, &perf_info); -#endif -#if _USE_MEM_MONITOR +#if LV_USE_MEM_MONITOR static lv_mem_monitor_t mem_info; lv_subject_init_pointer(&sysmon_mem.subject, &mem_info); - sysmon_mem.timer = lv_timer_create(mem_update_timer_cb, SYSMON_REFR_PERIOD_DEF, &mem_info); + sysmon_mem.timer = lv_timer_create(mem_update_timer_cb, LV_SYSMON_REFR_PERIOD_DEF, &mem_info); #endif } void _lv_sysmon_builtin_deinit(void) { -#if _USE_PERF_MONITOR - lv_timer_delete(sysmon_perf.timer); -#endif - -#if _USE_MEM_MONITOR +#if LV_USE_MEM_MONITOR lv_timer_delete(sysmon_mem.timer); #endif } -lv_obj_t * lv_sysmon_create(lv_obj_t * parent) +lv_obj_t * lv_sysmon_create(lv_display_t * disp) { LV_LOG_INFO("begin"); - lv_obj_t * label = lv_label_create(parent); + if(disp == NULL) disp = lv_display_get_default(); + if(disp == NULL) { + LV_LOG_WARN("There is no default display"); + return NULL; + } + + lv_obj_t * label = lv_label_create(lv_display_get_layer_sys(disp)); lv_obj_set_style_bg_opa(label, LV_OPA_50, 0); lv_obj_set_style_bg_color(label, lv_color_black(), 0); lv_obj_set_style_text_color(label, lv_color_white(), 0); @@ -105,16 +94,94 @@ lv_obj_t * lv_sysmon_create(lv_obj_t * parent) return label; } +#if LV_USE_PERF_MONITOR + +void lv_sysmon_show_performance(lv_display_t * disp) +{ + if(disp == NULL) disp = lv_display_get_default(); + if(disp == NULL) { + LV_LOG_WARN("There is no default display"); + return; + } + + disp->perf_label = lv_sysmon_create(disp); + if(disp->perf_label == NULL) { + LV_LOG_WARN("Couldn't create sysmon"); + return; + } + + lv_subject_init_pointer(&disp->perf_sysmon_backend.subject, &disp->perf_sysmon_info); + lv_obj_align(disp->perf_label, LV_USE_PERF_MONITOR_POS, 0, 0); + lv_subject_add_observer_obj(&disp->perf_sysmon_backend.subject, perf_observer_cb, disp->perf_label, NULL); + disp->perf_sysmon_backend.timer = lv_timer_create(perf_update_timer_cb, LV_SYSMON_REFR_PERIOD_DEF, disp); + lv_display_add_event_cb(disp, perf_monitor_disp_event_cb, LV_EVENT_ALL, NULL); + +#if LV_USE_PERF_MONITOR_LOG_MODE + lv_obj_add_flag(disp->perf_label, LV_OBJ_FLAG_HIDDEN); +#else + lv_obj_remove_flag(disp->perf_label, LV_OBJ_FLAG_HIDDEN); +#endif +} + +void lv_sysmon_hide_performance(lv_display_t * disp) +{ + if(disp == NULL) disp = lv_display_get_default(); + if(disp == NULL) { + LV_LOG_WARN("There is no default display"); + return; + } + + lv_obj_add_flag(disp->perf_label, LV_OBJ_FLAG_HIDDEN); +} + +#endif + +#if LV_USE_MEM_MONITOR + +void lv_sysmon_show_memory(lv_display_t * disp) +{ + if(disp == NULL) disp = lv_display_get_default(); + if(disp == NULL) { + LV_LOG_WARN("There is no default display"); + return; + } + + disp->mem_label = lv_sysmon_create(disp); + if(disp->mem_label == NULL) { + LV_LOG_WARN("Couldn't create sysmon"); + return; + } + + lv_obj_align(disp->mem_label, LV_USE_MEM_MONITOR_POS, 0, 0); + lv_subject_add_observer_obj(&sysmon_mem.subject, mem_observer_cb, disp->mem_label, NULL); + + lv_obj_remove_flag(disp->mem_label, LV_OBJ_FLAG_HIDDEN); +} + +void lv_sysmon_hide_memory(lv_display_t * disp) +{ + if(disp == NULL) disp = lv_display_get_default(); + if(disp == NULL) { + LV_LOG_WARN("There is no default display"); + return; + } + + lv_obj_add_flag(disp->mem_label, LV_OBJ_FLAG_HIDDEN); +} + +#endif + /********************** * STATIC FUNCTIONS **********************/ -#if _USE_PERF_MONITOR +#if LV_USE_PERF_MONITOR static void perf_monitor_disp_event_cb(lv_event_t * e) { + lv_display_t * disp = lv_event_get_target(e); lv_event_code_t code = lv_event_get_code(e); - lv_sysmon_perf_info_t * info = (lv_sysmon_perf_info_t *)lv_subject_get_pointer(&sysmon_perf.subject); + lv_sysmon_perf_info_t * info = &disp->perf_sysmon_info; switch(code) { case LV_EVENT_REFR_START: @@ -152,6 +219,10 @@ static void perf_monitor_disp_event_cb(lv_event_t * e) info->measured.flush_not_in_render_elaps_sum += lv_tick_elaps(info->measured.flush_not_in_render_start); } break; + case LV_EVENT_DELETE: + lv_timer_delete(disp->perf_sysmon_backend.timer); + lv_subject_deinit(&disp->perf_sysmon_backend.subject); + break; default: break; } @@ -159,24 +230,11 @@ static void perf_monitor_disp_event_cb(lv_event_t * e) static void perf_update_timer_cb(lv_timer_t * t) { - /*Wait for a display*/ - if(!sysmon_perf.inited && lv_display_get_default()) { - lv_display_add_event_cb(lv_display_get_default(), perf_monitor_disp_event_cb, LV_EVENT_ALL, NULL); - - lv_obj_t * obj1 = lv_sysmon_create(lv_layer_sys()); - lv_obj_align(obj1, LV_USE_PERF_MONITOR_POS, 0, 0); - lv_subject_add_observer_obj(&sysmon_perf.subject, perf_observer_cb, obj1, NULL); -#if LV_USE_PERF_MONITOR_LOG_MODE - lv_obj_add_flag(obj1, LV_OBJ_FLAG_HIDDEN); -#endif - sysmon_perf.inited = true; - } - - if(!sysmon_perf.inited) return; + lv_display_t * disp = lv_timer_get_user_data(t); uint32_t LV_SYSMON_GET_IDLE(void); - lv_sysmon_perf_info_t * info = lv_timer_get_user_data(t); + lv_sysmon_perf_info_t * info = &disp->perf_sysmon_info; info->calculated.run_cnt++; uint32_t time_since_last_report = lv_tick_elaps(info->measured.last_report_timestamp); @@ -204,7 +262,7 @@ static void perf_update_timer_cb(lv_timer_t * t) info->calculated.fps_avg_total = ((info->calculated.fps_avg_total * (info->calculated.run_cnt - 1)) + info->calculated.fps) / info->calculated.run_cnt; - lv_subject_set_pointer(&sysmon_perf.subject, info); + lv_subject_set_pointer(&disp->perf_sysmon_backend.subject, info); lv_sysmon_perf_info_t prev_info = *info; lv_memzero(info, sizeof(lv_sysmon_perf_info_t)); @@ -244,20 +302,10 @@ static void perf_observer_cb(lv_observer_t * observer, lv_subject_t * subject) #endif -#if _USE_MEM_MONITOR +#if LV_USE_MEM_MONITOR static void mem_update_timer_cb(lv_timer_t * t) { - /*Wait for a display*/ - if(!sysmon_mem.inited && lv_display_get_default()) { - lv_obj_t * obj2 = lv_sysmon_create(lv_layer_sys()); - lv_obj_align(obj2, LV_USE_MEM_MONITOR_POS, 0, 0); - lv_subject_add_observer_obj(&sysmon_mem.subject, mem_observer_cb, obj2, NULL); - sysmon_mem.inited = true; - } - - if(!sysmon_mem.inited) return; - lv_mem_monitor_t * mem_mon = lv_timer_get_user_data(t); lv_mem_monitor(mem_mon); lv_subject_set_pointer(&sysmon_mem.subject, mem_mon); diff --git a/src/others/sysmon/lv_sysmon.h b/src/others/sysmon/lv_sysmon.h index 849e4d86d4..e106eadd5f 100644 --- a/src/others/sysmon/lv_sysmon.h +++ b/src/others/sysmon/lv_sysmon.h @@ -35,14 +35,13 @@ extern "C" { * TYPEDEFS **********************/ -typedef struct { +struct _lv_sysmon_backend_data_t { lv_subject_t subject; lv_timer_t * timer; - bool inited; -} lv_sysmon_backend_data_t; +}; #if LV_USE_PERF_MONITOR -typedef struct { +struct _lv_sysmon_perf_info_t { struct { bool inited; uint32_t refr_start; @@ -71,7 +70,7 @@ typedef struct { uint32_t run_cnt; } calculated; -} lv_sysmon_perf_info_t; +}; #endif /********************** @@ -79,18 +78,43 @@ typedef struct { **********************/ /** - * Create a system monitor object. - * @param parent pointer to an object, it will be the parent of the new system monitor - * @return pointer to the new system monitor object + * Create a new system monitor label + * @param disp create the sys. mon. on this display's system layer + * @return the create label */ -lv_obj_t * lv_sysmon_create(lv_obj_t * parent); +lv_obj_t * lv_sysmon_create(lv_display_t * disp); + +#if LV_USE_PERF_MONITOR /** - * Set the refresh period of the system monitor object - * @param obj pointer to a system monitor object - * @param period the refresh period in milliseconds + * Show system performance monitor: CPU usage and FPS count + * @param disp target display, NULL: use the default displays */ -void lv_sysmon_set_refr_period(lv_obj_t * obj, uint32_t period); +void lv_sysmon_show_performance(lv_display_t * disp); + +/** + * Hide system performance monitor + * @param disp target display, NULL: use the default + */ +void lv_sysmon_hide_performance(lv_display_t * disp); + +#endif /*LV_USE_PERF_MONITOR*/ + +#if LV_USE_MEM_MONITOR + +/** + * Show system memory monitor: used memory and the memory fragmentation + * @param disp target display, NULL: use the default displays + */ +void lv_sysmon_show_memory(lv_display_t * disp); + +/** + * Hide system memory monitor + * @param disp target display, NULL: use the default displays + */ +void lv_sysmon_hide_memory(lv_display_t * disp); + +#endif /*LV_USE_MEM_MONITOR*/ /** * Initialize built-in system monitor, such as performance and memory monitor. diff --git a/tests/src/lv_test_conf.h b/tests/src/lv_test_conf.h index 91cd9c5061..ccf0876030 100644 --- a/tests/src/lv_test_conf.h +++ b/tests/src/lv_test_conf.h @@ -116,8 +116,6 @@ typedef void * lv_user_data_t; #define LV_DRAW_BUF_ALIGN 852 /*For screenshots*/ -#undef LV_USE_PERF_MONITOR -#undef LV_USE_MEM_MONITOR #undef LV_DPI_DEF #define LV_DPI_DEF 130 #endif diff --git a/tests/src/lv_test_conf_full.h b/tests/src/lv_test_conf_full.h index 1988c60003..24eaf51dc5 100644 --- a/tests/src/lv_test_conf_full.h +++ b/tests/src/lv_test_conf_full.h @@ -84,6 +84,8 @@ #define LV_USE_FILE_EXPLORER 1 #define LV_USE_TINY_TTF 1 #define LV_USE_SYSMON 1 +#define LV_USE_MEM_MONITOR 1 +#define LV_USE_PERF_MONITOR 1 #define LV_USE_SNAPSHOT 1 #define LV_USE_THORVG_INTERNAL 1 #define LV_USE_LZ4_INTERNAL 1 diff --git a/tests/src/lv_test_init.c b/tests/src/lv_test_init.c index bda98e525e..e5ab3bb79c 100644 --- a/tests/src/lv_test_init.c +++ b/tests/src/lv_test_init.c @@ -20,6 +20,14 @@ void lv_test_init(void) { lv_init(); hal_init(); +#if LV_USE_SYSMON +#if LV_USE_MEM_MONITOR + lv_sysmon_hide_memory(NULL); +#endif +#if LV_USE_PERF_MONITOR + lv_sysmon_hide_performance(NULL); +#endif +#endif } void lv_test_deinit(void) diff --git a/tests/src/test_cases/test_observer.c b/tests/src/test_cases/test_observer.c index 46667ef4a1..7122a4126c 100644 --- a/tests/src/test_cases/test_observer.c +++ b/tests/src/test_cases/test_observer.c @@ -504,4 +504,26 @@ void test_observer_dropdown_value(void) TEST_ASSERT_EQUAL(0, lv_subject_get_int(&subject)); } +void test_observer_deinit(void) +{ + static lv_subject_t subject; + + uint32_t mem = lv_test_get_free_mem(); + uint32_t i; + for(i = 0; i < 64; i++) { + lv_obj_t * obj1 = lv_slider_create(lv_screen_active()); + lv_obj_t * obj2 = lv_slider_create(lv_screen_active()); + + lv_subject_init_int(&subject, 30); + lv_slider_bind_value(obj1, &subject); + lv_slider_bind_value(obj2, &subject); + lv_subject_add_observer(&subject, observer_int, NULL); + lv_obj_delete(obj1); + lv_subject_deinit(&subject); + lv_obj_delete(obj2); + } + + TEST_ASSERT_MEM_LEAK_LESS_THAN(mem, 32); +} + #endif