1 /**
2  * @file lv_msg.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "lv_msg.h"
10 #if LV_USE_MSG
11 
12 #include "../../../misc/lv_assert.h"
13 #include "../../../misc/lv_ll.h"
14 
15 /*********************
16  *      DEFINES
17  *********************/
18 
19 /**********************
20  *      TYPEDEFS
21  **********************/
22 
23 typedef struct {
24     uint32_t msg_id;
25     lv_msg_subscribe_cb_t callback;
26     void * user_data;
27     void * _priv_data;      /*Internal: used only store 'obj' in lv_obj_subscribe*/
28 } sub_dsc_t;
29 
30 /**********************
31  *  STATIC PROTOTYPES
32  **********************/
33 
34 static void notify(lv_msg_t * m);
35 static void obj_notify_cb(void * s, lv_msg_t * m);
36 static void obj_delete_event_cb(lv_event_t * e);
37 
38 /**********************
39  *  STATIC VARIABLES
40  **********************/
41 static lv_ll_t subs_ll;
42 
43 /**********************
44  *  GLOBAL VARIABLES
45  **********************/
46 lv_event_code_t LV_EVENT_MSG_RECEIVED;
47 
48 /**********************
49  *      MACROS
50  **********************/
51 
52 /**********************
53  *   GLOBAL FUNCTIONS
54  **********************/
55 
lv_msg_init(void)56 void lv_msg_init(void)
57 {
58     LV_EVENT_MSG_RECEIVED = lv_event_register_id();
59     _lv_ll_init(&subs_ll, sizeof(sub_dsc_t));
60 }
61 
lv_msg_subsribe(uint32_t msg_id,lv_msg_subscribe_cb_t cb,void * user_data)62 void * lv_msg_subsribe(uint32_t msg_id, lv_msg_subscribe_cb_t cb, void * user_data)
63 {
64     sub_dsc_t * s = _lv_ll_ins_tail(&subs_ll);
65     LV_ASSERT_MALLOC(s);
66     if(s == NULL) return NULL;
67 
68     lv_memset_00(s, sizeof(*s));
69 
70     s->msg_id = msg_id;
71     s->callback = cb;
72     s->user_data = user_data;
73     return s;
74 }
75 
lv_msg_subsribe_obj(uint32_t msg_id,lv_obj_t * obj,void * user_data)76 void * lv_msg_subsribe_obj(uint32_t msg_id, lv_obj_t * obj, void * user_data)
77 {
78     sub_dsc_t * s = lv_msg_subsribe(msg_id, obj_notify_cb, user_data);
79     if(s == NULL) return NULL;
80     s->_priv_data = obj;
81 
82     /*If not added yet, add a delete event cb which automatically unsubcribes the object*/
83     sub_dsc_t * s_first = lv_obj_get_event_user_data(obj, obj_delete_event_cb);
84     if(s_first == NULL) {
85         lv_obj_add_event_cb(obj, obj_delete_event_cb, LV_EVENT_DELETE, s);
86     }
87     return s;
88 }
89 
lv_msg_unsubscribe(void * s)90 void lv_msg_unsubscribe(void * s)
91 {
92     LV_ASSERT_NULL(s);
93     _lv_ll_remove(&subs_ll, s);
94     lv_mem_free(s);
95 }
96 
lv_msg_unsubscribe_obj(uint32_t msg_id,lv_obj_t * obj)97 uint32_t lv_msg_unsubscribe_obj(uint32_t msg_id, lv_obj_t * obj)
98 {
99     uint32_t cnt = 0;
100     sub_dsc_t * s = _lv_ll_get_head(&subs_ll);
101     while(s) {
102         sub_dsc_t * s_next = _lv_ll_get_next(&subs_ll, s);
103         if(s->callback == obj_notify_cb &&
104            (s->msg_id == LV_MSG_ID_ANY || s->msg_id == msg_id) &&
105            (obj == NULL || s->_priv_data == obj)) {
106             lv_msg_unsubscribe(s);
107             cnt++;
108         }
109 
110         s = s_next;
111     }
112 
113     return cnt;
114 }
115 
lv_msg_send(uint32_t msg_id,const void * payload)116 void lv_msg_send(uint32_t msg_id, const void * payload)
117 {
118     lv_msg_t m;
119     lv_memset_00(&m, sizeof(m));
120     m.id = msg_id;
121     m.payload = payload;
122     notify(&m);
123 }
124 
lv_msg_get_id(lv_msg_t * m)125 uint32_t lv_msg_get_id(lv_msg_t * m)
126 {
127     return m->id;
128 }
129 
lv_msg_get_payload(lv_msg_t * m)130 const void * lv_msg_get_payload(lv_msg_t * m)
131 {
132     return m->payload;
133 }
134 
lv_msg_get_user_data(lv_msg_t * m)135 void * lv_msg_get_user_data(lv_msg_t * m)
136 {
137     return m->user_data;
138 }
139 
lv_event_get_msg(lv_event_t * e)140 lv_msg_t * lv_event_get_msg(lv_event_t * e)
141 {
142     if(e->code == LV_EVENT_MSG_RECEIVED) {
143         return lv_event_get_param(e);
144     }
145     else {
146         LV_LOG_WARN("Not interpreted with this event code");
147         return NULL;
148     }
149 }
150 
151 /**********************
152  *   STATIC FUNCTIONS
153  **********************/
154 
notify(lv_msg_t * m)155 static void notify(lv_msg_t * m)
156 {
157     sub_dsc_t * s;
158     _LV_LL_READ(&subs_ll, s) {
159         if(s->msg_id == m->id && s->callback) {
160             m->user_data = s->user_data;
161             m->_priv_data = s->_priv_data;
162             s->callback(s, m);
163         }
164     }
165 }
166 
obj_notify_cb(void * s,lv_msg_t * m)167 static void obj_notify_cb(void * s, lv_msg_t * m)
168 {
169     LV_UNUSED(s);
170     lv_event_send(m->_priv_data, LV_EVENT_MSG_RECEIVED, m);
171 }
172 
obj_delete_event_cb(lv_event_t * e)173 static void obj_delete_event_cb(lv_event_t * e)
174 {
175     lv_obj_t * obj = lv_event_get_target(e);
176 
177     sub_dsc_t * s = _lv_ll_get_head(&subs_ll);
178     sub_dsc_t * s_next;
179     while(s) {
180         /*On unsubscribe the list changes s becomes invalid so get next item while it's surely valid*/
181         s_next = _lv_ll_get_next(&subs_ll, s);
182         if(s->_priv_data == obj) {
183             lv_msg_unsubscribe(s);
184         }
185         s = s_next;
186     }
187 }
188 
189 #endif /*LV_USE_MSG*/
190