1 /**
2  * @file lv_circle_buf.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 
10 #include "lv_assert.h"
11 
12 #include "lv_circle_buf.h"
13 #include "lv_array.h"
14 
15 /*********************
16  *      DEFINES
17  *********************/
18 
19 /**********************
20  *      TYPEDEFS
21  **********************/
22 
23 struct _lv_circle_buf_t {
24     lv_array_t array;
25     uint32_t head;
26     uint32_t tail;    /**< The next write position */
27 
28     bool inner_alloc; /**< true: the array is allocated by the buffer, false: the array is created from an external buffer */
29 };
30 
31 /**********************
32  *  STATIC PROTOTYPES
33  **********************/
34 
35 static void circle_buf_prepare_empty(lv_circle_buf_t * circle_buf);
36 
37 /**********************
38  *  GLOBAL VARIABLES
39  **********************/
40 
41 /**********************
42  *  STATIC VARIABLES
43  **********************/
44 
45 /**********************
46  *      MACROS
47  **********************/
48 
49 /**********************
50  *   GLOBAL FUNCTIONS
51  **********************/
52 
lv_circle_buf_create(const uint32_t capacity,const uint32_t element_size)53 lv_circle_buf_t * lv_circle_buf_create(const uint32_t capacity, const uint32_t element_size)
54 {
55     lv_circle_buf_t * circle_buf = lv_malloc(sizeof(lv_circle_buf_t));
56     LV_ASSERT_MALLOC(circle_buf);
57 
58     if(circle_buf == NULL) {
59         return NULL;
60     }
61 
62     lv_array_init(&circle_buf->array, capacity, element_size);
63     circle_buf->head = 0;
64     circle_buf->tail = 0;
65     circle_buf->inner_alloc = true;
66 
67     circle_buf_prepare_empty(circle_buf);
68 
69     return circle_buf;
70 }
71 
lv_circle_buf_create_from_buf(void * buf,const uint32_t capacity,const uint32_t element_size)72 lv_circle_buf_t * lv_circle_buf_create_from_buf(void * buf, const uint32_t capacity, const uint32_t element_size)
73 {
74     LV_ASSERT_NULL(buf);
75 
76     lv_circle_buf_t * circle_buf = lv_malloc(sizeof(lv_circle_buf_t));
77     LV_ASSERT_MALLOC(circle_buf);
78 
79     if(circle_buf == NULL) {
80         return NULL;
81     }
82 
83     lv_array_init_from_buf(&circle_buf->array, buf, capacity, element_size);
84     circle_buf->head = 0;
85     circle_buf->tail = 0;
86     circle_buf->inner_alloc = false;
87 
88     circle_buf_prepare_empty(circle_buf);
89 
90     return circle_buf;
91 }
92 
lv_circle_buf_create_from_array(const lv_array_t * array)93 lv_circle_buf_t * lv_circle_buf_create_from_array(const lv_array_t * array)
94 {
95     LV_ASSERT_NULL(array);
96     if(array == NULL) {
97         return NULL;
98     }
99 
100     lv_circle_buf_t * circle_buf = lv_malloc(sizeof(lv_circle_buf_t));
101     LV_ASSERT_MALLOC(circle_buf);
102 
103     if(circle_buf == NULL) {
104         return NULL;
105     }
106 
107     circle_buf->array = *array;
108     circle_buf->head = 0;
109     circle_buf->tail = 0;
110     circle_buf->inner_alloc = false;
111 
112     circle_buf_prepare_empty(circle_buf);
113 
114     return circle_buf;
115 }
116 
lv_circle_buf_resize(lv_circle_buf_t * circle_buf,const uint32_t capacity)117 lv_result_t lv_circle_buf_resize(lv_circle_buf_t * circle_buf, const uint32_t capacity)
118 {
119     LV_ASSERT_NULL(circle_buf);
120 
121     if(lv_array_resize(&circle_buf->array, capacity) == false) {
122         return LV_RESULT_INVALID;
123     }
124 
125     circle_buf->head = 0;
126     circle_buf->tail = 0;
127 
128     circle_buf_prepare_empty(circle_buf);
129 
130     return LV_RESULT_OK;
131 }
132 
lv_circle_buf_destroy(lv_circle_buf_t * circle_buf)133 void lv_circle_buf_destroy(lv_circle_buf_t * circle_buf)
134 {
135     LV_ASSERT_NULL(circle_buf);
136 
137     lv_array_deinit(&circle_buf->array);
138 
139     lv_free(circle_buf);
140 }
141 
lv_circle_buf_size(const lv_circle_buf_t * circle_buf)142 uint32_t lv_circle_buf_size(const lv_circle_buf_t * circle_buf)
143 {
144     LV_ASSERT_NULL(circle_buf);
145 
146     return circle_buf->tail - circle_buf->head;
147 }
148 
lv_circle_buf_capacity(const lv_circle_buf_t * circle_buf)149 uint32_t lv_circle_buf_capacity(const lv_circle_buf_t * circle_buf)
150 {
151     LV_ASSERT_NULL(circle_buf);
152 
153     return lv_array_capacity(&circle_buf->array);
154 }
155 
lv_circle_buf_remain(const lv_circle_buf_t * circle_buf)156 uint32_t lv_circle_buf_remain(const lv_circle_buf_t * circle_buf)
157 {
158     LV_ASSERT_NULL(circle_buf);
159 
160     return lv_circle_buf_capacity(circle_buf) - lv_circle_buf_size(circle_buf);
161 }
162 
lv_circle_buf_is_empty(const lv_circle_buf_t * circle_buf)163 bool lv_circle_buf_is_empty(const lv_circle_buf_t * circle_buf)
164 {
165     LV_ASSERT_NULL(circle_buf);
166 
167     return !lv_circle_buf_size(circle_buf);
168 }
169 
lv_circle_buf_is_full(const lv_circle_buf_t * circle_buf)170 bool lv_circle_buf_is_full(const lv_circle_buf_t * circle_buf)
171 {
172     LV_ASSERT_NULL(circle_buf);
173 
174     return !lv_circle_buf_remain(circle_buf);
175 }
176 
lv_circle_buf_reset(lv_circle_buf_t * circle_buf)177 void lv_circle_buf_reset(lv_circle_buf_t * circle_buf)
178 {
179     LV_ASSERT_NULL(circle_buf);
180 
181     lv_array_clear(&circle_buf->array);
182     circle_buf->head = 0;
183     circle_buf->tail = 0;
184 }
185 
lv_circle_buf_head(const lv_circle_buf_t * circle_buf)186 void * lv_circle_buf_head(const lv_circle_buf_t * circle_buf)
187 {
188     LV_ASSERT_NULL(circle_buf);
189 
190     return lv_array_at(&circle_buf->array,
191                        circle_buf->head % lv_circle_buf_capacity(circle_buf));
192 }
193 
lv_circle_buf_tail(const lv_circle_buf_t * circle_buf)194 void * lv_circle_buf_tail(const lv_circle_buf_t * circle_buf)
195 {
196     LV_ASSERT_NULL(circle_buf);
197 
198     return lv_array_at(&circle_buf->array,
199                        circle_buf->tail % lv_circle_buf_capacity(circle_buf));
200 }
201 
lv_circle_buf_read(lv_circle_buf_t * circle_buf,void * data)202 lv_result_t lv_circle_buf_read(lv_circle_buf_t * circle_buf, void * data)
203 {
204     LV_ASSERT_NULL(circle_buf);
205 
206     if(lv_circle_buf_is_empty(circle_buf)) {
207         circle_buf->head = 0;
208         circle_buf->tail = 0;
209         return LV_RESULT_INVALID;
210     }
211 
212     lv_circle_buf_peek_at(circle_buf, 0, data);
213     circle_buf->head++;
214 
215     return LV_RESULT_OK;
216 }
217 
lv_circle_buf_write(lv_circle_buf_t * circle_buf,const void * data)218 lv_result_t lv_circle_buf_write(lv_circle_buf_t * circle_buf, const void * data)
219 {
220     LV_ASSERT_NULL(circle_buf);
221 
222     if(lv_circle_buf_is_full(circle_buf)) {
223         return LV_RESULT_INVALID;
224     }
225 
226     lv_array_assign(&circle_buf->array, circle_buf->tail % lv_circle_buf_capacity(circle_buf), data);
227     circle_buf->tail++;
228 
229     return LV_RESULT_OK;
230 }
231 
lv_circle_buf_fill(lv_circle_buf_t * circle_buf,uint32_t count,lv_circle_buf_fill_cb_t fill_cb,void * user_data)232 uint32_t lv_circle_buf_fill(lv_circle_buf_t * circle_buf, uint32_t count, lv_circle_buf_fill_cb_t fill_cb,
233                             void * user_data)
234 {
235     LV_ASSERT_NULL(circle_buf);
236     LV_ASSERT_NULL(fill_cb);
237 
238     uint32_t filled = 0;
239     while(count > 0 && !lv_circle_buf_is_full(circle_buf)) {
240         void * data = lv_circle_buf_tail(circle_buf);
241         if(fill_cb(data, circle_buf->array.element_size, (int32_t)filled, user_data) == LV_RESULT_OK) {
242             circle_buf->tail++;
243             filled++;
244         }
245         else break;
246 
247         count--;
248     }
249 
250     return filled;
251 }
252 
lv_circle_buf_skip(lv_circle_buf_t * circle_buf)253 lv_result_t lv_circle_buf_skip(lv_circle_buf_t * circle_buf)
254 {
255     LV_ASSERT_NULL(circle_buf);
256 
257     if(lv_circle_buf_is_empty(circle_buf)) {
258         circle_buf->head = 0;
259         circle_buf->tail = 0;
260         return LV_RESULT_INVALID;
261     }
262 
263     circle_buf->head++;
264 
265     return LV_RESULT_OK;
266 }
267 
lv_circle_buf_peek(const lv_circle_buf_t * circle_buf,void * data)268 lv_result_t lv_circle_buf_peek(const lv_circle_buf_t * circle_buf, void * data)
269 {
270     LV_ASSERT_NULL(circle_buf);
271     LV_ASSERT_NULL(data);
272 
273     return lv_circle_buf_peek_at(circle_buf, 0, data);
274 }
275 
lv_circle_buf_peek_at(const lv_circle_buf_t * circle_buf,const uint32_t index,void * data)276 lv_result_t lv_circle_buf_peek_at(const lv_circle_buf_t * circle_buf, const uint32_t index, void * data)
277 {
278     LV_ASSERT_NULL(circle_buf);
279     LV_ASSERT_NULL(data);
280 
281     const uint32_t real_index = (index % lv_circle_buf_size(circle_buf) + circle_buf->head) % lv_circle_buf_capacity(
282                                     circle_buf);
283     lv_memcpy(data, lv_array_at(&circle_buf->array, real_index), circle_buf->array.element_size);
284 
285     return LV_RESULT_OK;
286 }
287 
288 /**********************
289  *   STATIC FUNCTIONS
290  **********************/
291 
circle_buf_prepare_empty(lv_circle_buf_t * circle_buf)292 static void circle_buf_prepare_empty(lv_circle_buf_t * circle_buf)
293 {
294     const uint32_t required = lv_array_capacity(&circle_buf->array) - lv_array_size(&circle_buf->array);
295     for(uint32_t i = 0; i < required; i++) lv_array_push_back(&circle_buf->array, NULL);
296 }
297