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