Branch data Line data Source code
1 : : /**
2 : : ***********************************************************************************************************************
3 : : * @file cb.c
4 : : * @author Diego Martínez García (dmg0345@gmail.com)
5 : : * @date 04-11-2023 21:33:15 (UTC)
6 : : * @version 1.0.0
7 : : * @copyright github.com/dmg0345/cb/blob/master/LICENSE
8 : : ***********************************************************************************************************************
9 : : */
10 : :
11 : : /** @defgroup cb_iapi_impl Internal API implementation */
12 : : /** @defgroup cb_papi_impl Public API implementation */
13 : :
14 : : /* Includes ----------------------------------------------------------------------------------------------------------*/
15 : : #include "cb/cb.h"
16 : : #include <string.h>
17 : :
18 : : /* Private types -----------------------------------------------------------------------------------------------------*/
19 : : /**
20 : : * @addtogroup cb_iapi_impl
21 : : * @{
22 : : */
23 : :
24 : : /**
25 : : * @}
26 : : */
27 : :
28 : : /* Private define ----------------------------------------------------------------------------------------------------*/
29 : : /**
30 : : * @addtogroup cb_iapi_impl
31 : : * @{
32 : : */
33 : :
34 : : /**
35 : : * @}
36 : : */
37 : :
38 : : /* Private macro -----------------------------------------------------------------------------------------------------*/
39 : : /**
40 : : * @addtogroup cb_iapi_impl
41 : : * @{
42 : : */
43 : :
44 : : #ifdef CB_USE_STDATOMIC
45 : : /** Critical variable assignment, load and store operations, with atomic support. */
46 : : /** @{ */
47 : : #define CB_CRIT_VAR_INIT(variable, value) (atomic_init(&(variable), (value)))
48 : : #define CB_CRIT_VAR_LOAD(variable) (atomic_load(&(variable)))
49 : : #define CB_CRIT_VAR_STORE(variable, value) (atomic_store(&(variable), (value)))
50 : : /** @} */
51 : : #else
52 : : /** Critical variable assignment, load and store operations, without atomic support. */
53 : : /** @{ */
54 : : #define CB_CRIT_VAR_INIT(variable, value) (variable) = (value)
55 : : #define CB_CRIT_VAR_LOAD(variable) (variable)
56 : : #define CB_CRIT_VAR_STORE(variable, value) (variable) = (value)
57 : : /** @} */
58 : : #endif
59 : :
60 : : /**
61 : : * @brief Casts a pointer to void to pointer to char for pointer arithmetic in units of one.
62 : : * @param[in] ptr The pointer to void to cast.
63 : : * @return The pointer to void to cast.
64 : : */
65 : : #define CB_CAST(ptr) ((char *)(ptr))
66 : :
67 : : /**
68 : : * @brief Casts a pointer to void to pointer to const char for pointer arithmetic in units of one.
69 : : * @param[in] ptr The pointer to void to cast.
70 : : * @return The pointer to void to cast.
71 : : */
72 : : #define CB_CONST_CAST(ptr) ((const char *)(ptr))
73 : :
74 : : /**
75 : : * @brief Checks if a circular buffer is subscribed to an event or multiple events specified.
76 : : * @param[in] cb The circular buffer.
77 : : * @param[in] evt The event or events to check if subscribed.
78 : : * @return @c true if subscribed to all the events specified and @c false if not.
79 : : */
80 : : #define CB_IS_SUB(cb, evt) (((cb)->evt_sub & (evt)) == (evt))
81 : :
82 : : /**
83 : : * @}
84 : : */
85 : :
86 : : /* Private variables -------------------------------------------------------------------------------------------------*/
87 : : /**
88 : : * @addtogroup cb_iapi_impl
89 : : * @{
90 : : */
91 : :
92 : : /**
93 : : * @}
94 : : */
95 : :
96 : : /* Private function prototypes ---------------------------------------------------------------------------------------*/
97 : : /**
98 : : * @addtogroup cb_iapi_impl
99 : : * @{
100 : : */
101 : :
102 : : /**
103 : : * @brief Triggers a ::cb_evt_id_read event, or falls back to the internal implementation if not subscribed.
104 : : * @param[in] cb Circular buffer context.
105 : : * @param[in] read_ptr The read pointer where to read the data from.
106 : : * @param[in] bytes The number of bytes to read from @p read_ptr and write to @p buffer.
107 : : * @param[in] buffer The buffer where to write data to.
108 : : * @retval ::cb_error_ok Success.
109 : : * @retval ::cb_error_evt The handling of the event resulted in error.
110 : : */
111 : : static cb_error_t
112 : : cb_evt_read(const cb_t * const cb, const void * const read_ptr, const size_t bytes, void * const buffer);
113 : :
114 : : /**
115 : : * @brief Triggers a ::cb_evt_id_write event, or falls back to the internal implementation if not subscribed.
116 : : * @param[in] cb Circular buffer context.
117 : : * @param[in] buffer The buffer where to read the data from.
118 : : * @param[in] bytes The number of bytes to read from @p buffer and write to @p write_ptr.
119 : : * @param[in] write_ptr The write pointer where to write the data to.
120 : : * @retval ::cb_error_ok Success.
121 : : * @retval ::cb_error_evt The handling of the event resulted in error.
122 : : */
123 : : static cb_error_t
124 : : cb_evt_write(const cb_t * const cb, const void * const buffer, const size_t bytes, void * const write_ptr);
125 : :
126 : : /**
127 : : * @brief Triggers a ::cb_evt_id_lock event, or falls back to the internal implementation if not subscribed.
128 : : * @param[in] cb Circular buffer context.
129 : : */
130 : : static void cb_evt_lock(const cb_t * const cb);
131 : :
132 : : /**
133 : : * @brief Triggers a ::cb_evt_id_unlock event, or falls back to the internal implementation if not subscribed.
134 : : * @param[in] cb Circular buffer context.
135 : : */
136 : : static void cb_evt_unlock(const cb_t * const cb);
137 : :
138 : : /**
139 : : * @brief Obtains the number of filled slots in the circular buffer.
140 : : * @param[in] cb Circular buffer context.
141 : : * @param[out] felems The number of filled elements from the read index to first write or end index, can be @c NULL.
142 : : * @param[out] selems The number of filled elements from the start index to write index, can be @c NULL.
143 : : * @return The number of filled slots.
144 : : */
145 : : static size_t cb_int_get_filled(const cb_t * const cb, size_t * const felems, size_t * const selems);
146 : :
147 : : /**
148 : : * @brief Obtains the number of unfilled slots in the circular buffer.
149 : : * @param[in] cb Circular buffer context.
150 : : * @param[out] felems The number of unfilled elements from the write index to first read or end index, can be @c NULL.
151 : : * @param[out] selems The number of unfilled elements from the start index to read index, can be @c NULL.
152 : : * @return The number of unfilled slots.
153 : : */
154 : : static size_t cb_int_get_unfilled(const cb_t * const cb, size_t * const felems, size_t * const selems);
155 : :
156 : : /**
157 : : * @}
158 : : */
159 : :
160 : : /* Private functions -------------------------------------------------------------------------------------------------*/
161 : : /**
162 : : * @addtogroup cb_iapi_impl
163 : : * @{
164 : : */
165 : :
166 : : /*--------------------------------------------------------------------------------------------------------------------*/
167 : : static cb_error_t
168 : 1746964 : cb_evt_read(const cb_t * const cb, const void * const read_ptr, const size_t bytes, void * const buffer)
169 : : {
170 : : // Check if subscribed to event, and call event handler if so.
171 [ + + ]: 1746964 : if (CB_IS_SUB(cb, cb_evt_id_read))
172 : : {
173 : 748 : cb_evt_t evt = {
174 : : .cb = cb,
175 : 748 : .user_data = cb->evt_user_data,
176 : : .id = cb_evt_id_read,
177 : : .data.read = {.read_ptr = read_ptr, .bytes = bytes, .buffer = buffer},
178 : : };
179 : 748 : return cb->evt_handler(&evt);
180 : : }
181 : :
182 : : // Otherwise, use built-in implementation.
183 : 1746216 : (void)memcpy(buffer, read_ptr, bytes);
184 : :
185 : 1746216 : return cb_error_ok;
186 : : }
187 : :
188 : : /*--------------------------------------------------------------------------------------------------------------------*/
189 : : static cb_error_t
190 : 1746964 : cb_evt_write(const cb_t * const cb, const void * const buffer, const size_t bytes, void * const write_ptr)
191 : : {
192 : : // Check if subscribed to event, and call event handler if so.
193 [ + + ]: 1746964 : if (CB_IS_SUB(cb, cb_evt_id_write))
194 : : {
195 : 748 : cb_evt_t evt = {
196 : : .cb = cb,
197 : 748 : .user_data = cb->evt_user_data,
198 : : .id = cb_evt_id_write,
199 : : .data.write = {.buffer = buffer, .bytes = bytes, .write_ptr = write_ptr},
200 : : };
201 : 748 : return cb->evt_handler(&evt);
202 : : }
203 : :
204 : : // Otherwise, use built-in implementation.
205 : 1746216 : (void)memcpy(write_ptr, buffer, bytes);
206 : :
207 : 1746216 : return cb_error_ok;
208 : : }
209 : :
210 : : /*--------------------------------------------------------------------------------------------------------------------*/
211 : 28578099 : static void cb_evt_lock(const cb_t * const cb)
212 : : {
213 [ + + ]: 28578099 : if (CB_IS_SUB(cb, cb_evt_id_lock))
214 : : {
215 : 24826087 : cb_evt_t evt = {
216 : : .cb = cb,
217 : 24826087 : .user_data = cb->evt_user_data,
218 : : .id = cb_evt_id_lock,
219 : : .data.lock.unused = 0U,
220 : : };
221 : 24826087 : (void)cb->evt_handler(&evt);
222 : : }
223 : :
224 : : // Internal implementation assumes no locking mechanisms.
225 : 29027662 : }
226 : :
227 : : /*--------------------------------------------------------------------------------------------------------------------*/
228 : 28711869 : static void cb_evt_unlock(const cb_t * const cb)
229 : : {
230 [ + + ]: 28711869 : if (CB_IS_SUB(cb, cb_evt_id_unlock))
231 : : {
232 : 25275650 : cb_evt_t evt = {
233 : : .cb = cb,
234 : 25275650 : .user_data = cb->evt_user_data,
235 : : .id = cb_evt_id_unlock,
236 : : .data.unlock.unused = 0U,
237 : : };
238 : 25275650 : (void)cb->evt_handler(&evt);
239 : : }
240 : :
241 : : // Internal implementation assumes no locking mechanisms.
242 : 28327396 : }
243 : :
244 : : /*--------------------------------------------------------------------------------------------------------------------*/
245 : 16717315 : static size_t cb_int_get_filled(const cb_t * const cb, size_t * const felems, size_t * const selems)
246 : : {
247 : : // Read critical variables to local ones and perform operation.
248 : 16717315 : const size_t write_idx = CB_CRIT_VAR_LOAD(cb->write_idx);
249 : 16717315 : const size_t read_idx = CB_CRIT_VAR_LOAD(cb->read_idx);
250 : :
251 : : // If empty, then nothing is filled.
252 [ + + ]: 16717315 : if (write_idx == read_idx)
253 : : {
254 : 15115175 : *felems = 0U;
255 : 15115175 : *selems = 0U;
256 : : }
257 : : // If full, everything is filled.
258 [ + + ][ + + ]: 1602140 : else if (((write_idx == (cb->buffer_length - 1U)) ? (0U) : (write_idx + 1U)) == read_idx)
259 : : {
260 [ + + ]: 410429 : *felems = (read_idx < write_idx) ? ((write_idx) - (read_idx)) : ((cb->buffer_length) - (read_idx));
261 [ + + ]: 447324 : *selems = (read_idx > write_idx) ? (write_idx) : (0U);
262 : : }
263 : : // Check if the elements from read index to end index and start index to write index are filled.
264 [ + + ]: 1191711 : else if (write_idx < read_idx)
265 : : {
266 : 416703 : *felems = cb->buffer_length - read_idx;
267 : 416703 : *selems = write_idx;
268 : : }
269 : : // Otherwise, the elements between read index and write index are filled.
270 : : else
271 : : {
272 : 775008 : *felems = write_idx - read_idx;
273 : 775008 : *selems = 0U;
274 : : }
275 : :
276 : 16717315 : return *felems + *selems;
277 : : }
278 : :
279 : : /*--------------------------------------------------------------------------------------------------------------------*/
280 : 12410879 : static size_t cb_int_get_unfilled(const cb_t * const cb, size_t * const felems, size_t * const selems)
281 : : {
282 : : // Read critical variables to local ones and perform operation.
283 : 12410879 : const size_t write_idx = CB_CRIT_VAR_LOAD(cb->write_idx);
284 : 12410879 : const size_t read_idx = CB_CRIT_VAR_LOAD(cb->read_idx);
285 [ + + ]: 12410879 : const size_t read_idx_lim = (read_idx == 0U) ? (cb->buffer_length - 1U) : (read_idx - 1U);
286 : :
287 : : // If empty, then everything is unfilled.
288 [ + + ]: 12410879 : if (write_idx == read_idx)
289 : : {
290 [ + + ]: 715774 : *felems = (read_idx_lim < write_idx) ? (cb->buffer_length - write_idx) : (read_idx_lim - write_idx);
291 [ + + ]: 783076 : *selems = (write_idx > read_idx_lim) ? (read_idx_lim) : (0U);
292 : : }
293 : : // If full, nothing is unfilled.
294 [ + + ]: 11695105 : else if (write_idx == read_idx_lim)
295 : : {
296 : 10807807 : *felems = 0U;
297 : 10807807 : *selems = 0U;
298 : : }
299 : : // Check if the elements from write index to end index and start index to read limit index are filled.
300 [ + + ]: 887298 : else if (read_idx_lim < write_idx)
301 : : {
302 : 272223 : *felems = cb->buffer_length - write_idx;
303 : 272223 : *selems = read_idx_lim;
304 : : }
305 : : // Otherwise, the elements between read limit index and write index are filled.
306 : : else
307 : : {
308 : 615075 : *felems = read_idx_lim - write_idx;
309 : 615075 : *selems = 0U;
310 : : }
311 : :
312 : 12410879 : return *felems + *selems;
313 : : }
314 : :
315 : : /**
316 : : * @}
317 : : */
318 : :
319 : : /* Exported functions ------------------------------------------------------------------------------------------------*/
320 : : /**
321 : : * @addtogroup cb_papi_impl
322 : : * @{
323 : : */
324 : :
325 : : /*--------------------------------------------------------------------------------------------------------------------*/
326 : 68 : cb_error_t cb_init(cb_t * const cb,
327 : : void * const buffer,
328 : : const size_t buffer_length,
329 : : const size_t elem_size,
330 : : const cb_evt_handler_t evt_handler,
331 : : const cb_evt_id_t evt_sub,
332 : : void * const evt_user_data)
333 : : {
334 : : // Sanity check on arguments.
335 [ + + ][ + + ]: 68 : if ((cb == NULL) || (buffer == NULL) || (buffer_length <= 1U) || (elem_size == 0U) ||
336 [ + + ]: 48 : ((evt_sub == cb_evt_id_none) && (evt_handler != NULL)) ||
337 [ + + ]: 44 : ((evt_sub != cb_evt_id_none) && (evt_handler == NULL)))
338 : : {
339 : : return cb_error_invalid_args;
340 : : }
341 : :
342 : : // Initialize.
343 : 40 : cb->buffer = buffer;
344 : 40 : cb->buffer_length = buffer_length;
345 : 40 : cb->elem_size = elem_size;
346 : 40 : CB_CRIT_VAR_INIT(cb->read_idx, 0U);
347 : 40 : CB_CRIT_VAR_INIT(cb->write_idx, 0U);
348 : 40 : cb->evt_handler = evt_handler;
349 : 40 : cb->evt_sub = evt_sub;
350 : 40 : cb->evt_user_data = evt_user_data;
351 : :
352 : 40 : return cb_error_ok;
353 : : }
354 : :
355 : : /*--------------------------------------------------------------------------------------------------------------------*/
356 : 12310848 : cb_error_t cb_write(cb_t * const cb, const void * const buffer, const size_t count)
357 : : {
358 : : // Sanity check for arguments.
359 [ + + ][ + + ]: 12310848 : if ((cb == NULL) || (buffer == NULL) || (count == 0U))
360 : : {
361 : : return cb_error_invalid_args;
362 : : }
363 : :
364 : : // Lock buffer for writing, in a single-producer single-consumer scenario nothing else can be writing by design
365 : : // thus a user provided lock is not necessary, in other scenarios, the user needs to provide a lock to guarantee
366 : : // that multiple threads are not writing at the same time. With this in consideration, we can guarantee that
367 : : // here onwards there will only be a single thread executing the write process.
368 : 12309758 : cb_evt_lock(cb);
369 : :
370 : : // Get number of unfilled slots and check if requested amount fits in the buffer, if a read is performed at the
371 : : // same time, this means that more space would become available but has no direct implication on the write as
372 : : // in any case case we are guaranteeing the amount of elements requested for write fit.
373 : 12408767 : size_t fe = 0U;
374 : 12408767 : size_t se = 0U;
375 : 12408767 : size_t we = cb_int_get_unfilled(cb, &fe, &se);
376 [ + + ]: 12408767 : if (count > we)
377 : : {
378 : 10807699 : cb_evt_unlock(cb);
379 : 10807699 : return cb_error_full;
380 : : }
381 : 1601068 : size_t write_idx = CB_CRIT_VAR_LOAD(cb->write_idx);
382 : 1601068 : we = count;
383 : :
384 : : // Perform first write.
385 : 1601068 : fe = (we > fe) ? (fe) : (we);
386 : 1601068 : we -= fe;
387 : 1601068 : fe *= cb->elem_size;
388 : 1601068 : cb_error_t error = cb_evt_write(cb, buffer, fe, CB_CAST(cb->buffer) + (write_idx * cb->elem_size));
389 [ + + ]: 1601068 : if (error != cb_error_ok)
390 : : {
391 : 4 : cb_evt_unlock(cb);
392 : 4 : return error;
393 : : }
394 : :
395 : : // Perform second write if any.
396 [ + + ]: 1601064 : if (we > 0U)
397 : : {
398 : : // Perform second write from the start index till the read index at most.
399 : 145896 : se = we * cb->elem_size;
400 : 145896 : error = cb_evt_write(cb, CB_CONST_CAST(buffer) + fe, se, cb->buffer);
401 [ + + ]: 145896 : if (error != cb_error_ok)
402 : : {
403 : 4 : cb_evt_unlock(cb);
404 : 4 : return error;
405 : : }
406 : : }
407 : :
408 : : // Update write index.
409 : 1601060 : write_idx += count;
410 [ + + ]: 1601060 : write_idx = (write_idx >= cb->buffer_length) ? (write_idx - cb->buffer_length) : (write_idx);
411 : :
412 : : // Update buffer details.
413 : 1601060 : CB_CRIT_VAR_STORE(cb->write_idx, write_idx);
414 : :
415 : : // Unlock buffer after writing and updating variables.
416 : 1601060 : cb_evt_unlock(cb);
417 : :
418 : 1601060 : return cb_error_ok;
419 : : }
420 : :
421 : : /*--------------------------------------------------------------------------------------------------------------------*/
422 : 16600564 : cb_error_t cb_read(cb_t * const cb, void * const buffer, const size_t count)
423 : : {
424 : : // Sanity check for arguments.
425 [ + + ][ + + ]: 16600564 : if ((cb == NULL) || (buffer == NULL) || (count == 0U))
426 : : {
427 : : return cb_error_invalid_args;
428 : : }
429 : :
430 : : // Lock buffer for reading, in a single-producer single-consumer scenario nothing else can be reading by design
431 : : // thus a user provided lock is not necessary, in other scenarios, the user needs to provide a lock to guarantee
432 : : // that multiple threads are not reading at the same time. With this in consideration, we can guarantee that
433 : : // here onwards there will only be a single thread executing the read process.
434 : 16598714 : cb_evt_lock(cb);
435 : :
436 : : // Get number of filled slots and check if requested amount fits in the buffer, if a write is performed at the
437 : : // same time, this means that more data would become available but has no direct implication on the read as
438 : : // in any case case we are guaranteeing the amount of elements requested for read exist.
439 : 16715203 : size_t fe = 0U;
440 : 16715203 : size_t se = 0U;
441 : 16715203 : size_t re = cb_int_get_filled(cb, &fe, &se);
442 [ + + ]: 16715203 : if (count > re)
443 : : {
444 : 15114131 : cb_evt_unlock(cb);
445 : 15114131 : return cb_error_empty;
446 : : }
447 : 1601072 : size_t read_idx = CB_CRIT_VAR_LOAD(cb->read_idx);
448 : 1601072 : re = count;
449 : :
450 : : // Perform first read.
451 : 1601072 : fe = (re > fe) ? (fe) : (re);
452 : 1601072 : re -= fe;
453 : 1601072 : fe *= cb->elem_size;
454 : 1601072 : cb_error_t error = cb_evt_read(cb, CB_CAST(cb->buffer) + (read_idx * cb->elem_size), fe, buffer);
455 [ + + ]: 1601072 : if (error != cb_error_ok)
456 : : {
457 : 4 : cb_evt_unlock(cb);
458 : 4 : return error;
459 : : }
460 : :
461 : : // Perform second read if any.
462 [ + + ]: 1601068 : if (re > 0U)
463 : : {
464 : 145892 : se = re * cb->elem_size;
465 : 145892 : error = cb_evt_read(cb, cb->buffer, se, CB_CAST(buffer) + fe);
466 [ + + ]: 145892 : if (error != cb_error_ok)
467 : : {
468 : 4 : cb_evt_unlock(cb);
469 : 4 : return error;
470 : : }
471 : : }
472 : :
473 : : // Update write index.
474 : 1601064 : read_idx += count;
475 [ + + ]: 1601064 : read_idx = (read_idx >= cb->buffer_length) ? (read_idx - cb->buffer_length) : (read_idx);
476 : :
477 : : // Update buffer details.
478 : 1601064 : CB_CRIT_VAR_STORE(cb->read_idx, read_idx);
479 : :
480 : : // Unlock buffer after writing and updating variables.
481 : 1601064 : cb_evt_unlock(cb);
482 : :
483 : 1601064 : return cb_error_ok;
484 : : }
485 : :
486 : : /*--------------------------------------------------------------------------------------------------------------------*/
487 : 2104 : cb_error_t cb_get_unfilled(cb_t * const cb, size_t * const count)
488 : : {
489 : : // Sanity check on arguments.
490 [ + + ]: 2104 : if ((cb == NULL) || (count == NULL))
491 : : {
492 : : return cb_error_invalid_args;
493 : : }
494 : :
495 : : // Lock.
496 : 2096 : cb_evt_lock(cb);
497 : : // Get number of unfilled slots.
498 : 2096 : size_t felems = 0U;
499 : 2096 : size_t selems = 0U;
500 : 2096 : *count = cb_int_get_unfilled(cb, &felems, &selems);
501 : : // Unlock.
502 : 2096 : cb_evt_unlock(cb);
503 : :
504 : 2096 : return cb_error_ok;
505 : : }
506 : :
507 : : /*--------------------------------------------------------------------------------------------------------------------*/
508 : 2104 : cb_error_t cb_get_filled(cb_t * const cb, size_t * const count)
509 : : {
510 : : // Sanity check on arguments.
511 [ + + ]: 2104 : if ((cb == NULL) || (count == NULL))
512 : : {
513 : : return cb_error_invalid_args;
514 : : }
515 : :
516 : : // Lock.
517 : 2096 : cb_evt_lock(cb);
518 : : // Get number of filled slots.
519 : 2096 : size_t felems = 0U;
520 : 2096 : size_t selems = 0U;
521 : 2096 : *count = cb_int_get_filled(cb, &felems, &selems);
522 : : // Unlock.
523 : 2096 : cb_evt_unlock(cb);
524 : :
525 : 2096 : return cb_error_ok;
526 : : }
527 : :
528 : : /*--------------------------------------------------------------------------------------------------------------------*/
529 : 24 : cb_error_t cb_is_empty(cb_t * const cb, bool * const is_empty)
530 : : {
531 : : // Sanity check on arguments.
532 [ + + ]: 24 : if ((cb == NULL) || (is_empty == NULL))
533 : : {
534 : : return cb_error_invalid_args;
535 : : }
536 : :
537 : : // Lock.
538 : 16 : cb_evt_lock(cb);
539 : : // Check if number of filled slots is zero to determine empty.
540 : 16 : size_t felems = 0U;
541 : 16 : size_t selems = 0U;
542 : 16 : *is_empty = (cb_int_get_filled(cb, &felems, &selems) == 0U);
543 : : // Unlock.
544 : 16 : cb_evt_unlock(cb);
545 : :
546 : 16 : return cb_error_ok;
547 : : }
548 : :
549 : : /*--------------------------------------------------------------------------------------------------------------------*/
550 : 24 : cb_error_t cb_is_full(cb_t * const cb, bool * const is_full)
551 : : {
552 : : // Sanity check on arguments.
553 [ + + ]: 24 : if ((cb == NULL) || (is_full == NULL))
554 : : {
555 : : return cb_error_invalid_args;
556 : : }
557 : :
558 : : // Lock.
559 : 16 : cb_evt_lock(cb);
560 : : // Check if number of unfilled slots is zero to determine full.
561 : 16 : size_t felems = 0U;
562 : 16 : size_t selems = 0U;
563 : 16 : *is_full = (cb_int_get_unfilled(cb, &felems, &selems) == 0U);
564 : : // Unlock.
565 : 16 : cb_evt_unlock(cb);
566 : :
567 : 16 : return cb_error_ok;
568 : : }
569 : :
570 : : /*--------------------------------------------------------------------------------------------------------------------*/
571 : 44 : cb_error_t cb_deinit(cb_t * const cb)
572 : : {
573 : : // Sanity check for arguments.
574 [ + + ]: 44 : if (cb == NULL)
575 : : {
576 : : return cb_error_invalid_args;
577 : : }
578 : :
579 : : // Deinitialize.
580 : 40 : cb->buffer = NULL;
581 : 40 : cb->buffer_length = 0U;
582 : 40 : cb->elem_size = 0U;
583 : 40 : CB_CRIT_VAR_STORE(cb->read_idx, 0U);
584 : 40 : CB_CRIT_VAR_STORE(cb->write_idx, 0U);
585 : 40 : cb->evt_handler = NULL;
586 : 40 : cb->evt_sub = cb_evt_id_none;
587 : 40 : cb->evt_user_data = NULL;
588 : :
589 : 40 : return cb_error_ok;
590 : : }
591 : :
592 : : /**
593 : : * @}
594 : : */
595 : :
596 : : /******************************************************************************************************END OF FILE*****/
|