/** * @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; /********************** * 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_unsubscribe_obj(uint32_t msg_id, lv_obj_t * obj) { uint32_t cnt = 0; sub_dsc_t * s = _lv_ll_get_head(&subs_ll); while(s) { sub_dsc_t * s_next = _lv_ll_get_next(&subs_ll, s); if(s->callback == obj_notify_cb && (s->msg_id == LV_MSG_ID_ANY || s->msg_id == msg_id) && (obj == NULL || s->_priv_data == obj)) { lv_msg_unsubscribe(s); cnt++; } s = s_next; } return cnt; } 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*/