diff --git a/doc/reference/kernel/other/ring_buffers.rst b/doc/reference/kernel/other/ring_buffers.rst index 788af1aa770..0252bbfe3a0 100644 --- a/doc/reference/kernel/other/ring_buffers.rst +++ b/doc/reference/kernel/other/ring_buffers.rst @@ -103,9 +103,6 @@ shouldn't be needed. Internal Operation ================== -The ring buffer always maintains an empty 32-bit word (byte in bytes mode) in -its data buffer to allow it to distinguish between empty and full states. - If the size of the data buffer is a power of two, the ring buffer uses efficient masking operations instead of expensive modulo operations when enqueuing and dequeuing data items. This option is applicable only for diff --git a/include/sys/ring_buffer.h b/include/sys/ring_buffer.h index e4b8654aa58..dd803c58723 100644 --- a/include/sys/ring_buffer.h +++ b/include/sys/ring_buffer.h @@ -21,6 +21,13 @@ extern "C" { #define SIZE32_OF(x) (sizeof((x))/sizeof(uint32_t)) +/* The limit is used by algorithm for distinguishing between empty and full + * state. + */ +#define RING_BUFFER_MAX_SIZE 0x80000000 + +#define RING_BUFFER_SIZE_ASSERT_MSG \ + "Size too big, if it is the ring buffer test check custom max size" /** * @brief A structure to represent a ring buffer */ @@ -46,6 +53,8 @@ struct ring_buf { uint8_t *buf8; } buf; uint32_t mask; /**< Modulo mask if size is a power of 2 */ + + struct k_spinlock lock; }; /** @@ -71,6 +80,8 @@ struct ring_buf { * @param pow Ring buffer size exponent. */ #define RING_BUF_ITEM_DECLARE_POW2(name, pow) \ + BUILD_ASSERT((1 << pow) < RING_BUFFER_MAX_SIZE,\ + RING_BUFFER_SIZE_ASSERT_MSG); \ static uint32_t _ring_buffer_data_##name[BIT(pow)]; \ struct ring_buf name = { \ .size = (BIT(pow)), \ @@ -93,6 +104,8 @@ struct ring_buf { * @param size32 Size of ring buffer (in 32-bit words). */ #define RING_BUF_ITEM_DECLARE_SIZE(name, size32) \ + BUILD_ASSERT(size32 < RING_BUFFER_MAX_SIZE,\ + RING_BUFFER_SIZE_ASSERT_MSG); \ static uint32_t _ring_buffer_data_##name[size32]; \ struct ring_buf name = { \ .size = size32, \ @@ -113,6 +126,8 @@ struct ring_buf { * @param size8 Size of ring buffer (in bytes). */ #define RING_BUF_DECLARE(name, size8) \ + BUILD_ASSERT(size8 < RING_BUFFER_MAX_SIZE,\ + RING_BUFFER_SIZE_ASSERT_MSG); \ static uint8_t _ring_buffer_data_##name[size8]; \ struct ring_buf name = { \ .size = size8, \ @@ -138,6 +153,8 @@ struct ring_buf { */ static inline void ring_buf_init(struct ring_buf *buf, uint32_t size, void *data) { + __ASSERT(size < RING_BUFFER_MAX_SIZE, RING_BUFFER_SIZE_ASSERT_MSG); + memset(buf, 0, sizeof(struct ring_buf)); buf->size = size; buf->buf.buf32 = (uint32_t *)data; @@ -148,27 +165,6 @@ static inline void ring_buf_init(struct ring_buf *buf, uint32_t size, void *data } } -/** @brief Determine free space based on ring buffer parameters. - * - * @note Function for internal use. - * - * @param size Ring buffer size. - * @param head Ring buffer head. - * @param tail Ring buffer tail. - * - * @return Ring buffer free space (in 32-bit words or bytes). - */ -static inline uint32_t z_ring_buf_custom_space_get(uint32_t size, uint32_t head, - uint32_t tail) -{ - if (tail < head) { - return head - tail - 1U; - } - - /* buf->tail > buf->head */ - return (size - tail) + head - 1U; -} - /** * @brief Determine if a ring buffer is empty. * @@ -202,7 +198,7 @@ static inline void ring_buf_reset(struct ring_buf *buf) */ static inline uint32_t ring_buf_space_get(struct ring_buf *buf) { - return z_ring_buf_custom_space_get(buf->size, buf->head, buf->tail); + return buf->size - (buf->tail - buf->head); } /** @@ -214,8 +210,7 @@ static inline uint32_t ring_buf_space_get(struct ring_buf *buf) */ static inline uint32_t ring_buf_capacity_get(struct ring_buf *buf) { - /* One element is used to distinguish between empty and full state. */ - return buf->size - 1; + return buf->size; } /** diff --git a/lib/os/ring_buffer.c b/lib/os/ring_buffer.c index 8d9fcbf56a4..4a8392a4ef2 100644 --- a/lib/os/ring_buffer.c +++ b/lib/os/ring_buffer.c @@ -9,6 +9,14 @@ #include #include +/* The weak function used to allow overwriting it in the test and trigger + * rewinding earlier. + */ +uint32_t __weak ring_buf_get_rewind_threshold(void) +{ + return RING_BUFFER_MAX_SIZE; +} + /** * Internal data structure for a buffer header. * @@ -21,6 +29,57 @@ struct ring_element { uint32_t value :8; /**< Room for small integral values */ }; +static uint32_t mod(struct ring_buf *buf, uint32_t val) +{ + return likely(buf->mask) ? val & buf->mask : val % buf->size; +} + +/* Check if indexes did not progress too far (too close to 32-bit wrapping). + * If so, then reduce all indexes by an arbitrary value. + */ +static void item_indexes_rewind(struct ring_buf *buf) +{ + uint32_t rewind; + uint32_t threshold = ring_buf_get_rewind_threshold(); + + if (buf->head < threshold) { + return; + } + + rewind = buf->size * (threshold / buf->size); + + k_spinlock_key_t key = k_spin_lock(&buf->lock); + + buf->tail -= rewind; + buf->head -= rewind; + k_spin_unlock(&buf->lock, key); +} + +/* Check if indexes did not progresses too far (too close to 32-bit wrapping). + * If so, then rewind all indexes by an arbitrary value. For byte mode temporary + * indexes must also be reduced. + */ +static void byte_indexes_rewind(struct ring_buf *buf) +{ + uint32_t rewind; + uint32_t threshold = ring_buf_get_rewind_threshold(); + + /* Checking head since it is the smallest index. */ + if (buf->head < threshold) { + return; + } + + rewind = buf->size * (threshold / buf->size); + + k_spinlock_key_t key = k_spin_lock(&buf->lock); + + buf->tail -= rewind; + buf->head -= rewind; + buf->misc.byte_mode.tmp_head -= rewind; + buf->misc.byte_mode.tmp_tail -= rewind; + k_spin_unlock(&buf->lock, key); +} + int ring_buf_item_put(struct ring_buf *buf, uint16_t type, uint8_t value, uint32_t *data, uint8_t size32) { @@ -29,7 +88,8 @@ int ring_buf_item_put(struct ring_buf *buf, uint16_t type, uint8_t value, space = ring_buf_space_get(buf); if (space >= (size32 + 1)) { struct ring_element *header = - (struct ring_element *)&buf->buf.buf32[buf->tail]; + (struct ring_element *)&buf->buf.buf32[mod(buf, buf->tail)]; + header->type = type; header->length = size32; header->value = value; @@ -39,14 +99,14 @@ int ring_buf_item_put(struct ring_buf *buf, uint16_t type, uint8_t value, index = (i + buf->tail + 1) & buf->mask; buf->buf.buf32[index] = data[i]; } - buf->tail = (buf->tail + size32 + 1) & buf->mask; } else { for (i = 0U; i < size32; ++i) { index = (i + buf->tail + 1) % buf->size; buf->buf.buf32[index] = data[i]; } - buf->tail = (buf->tail + size32 + 1) % buf->size; } + + buf->tail = buf->tail + size32 + 1; rc = 0U; } else { buf->misc.item_mode.dropped_put_count++; @@ -66,7 +126,7 @@ int ring_buf_item_get(struct ring_buf *buf, uint16_t *type, uint8_t *value, return -EAGAIN; } - header = (struct ring_element *) &buf->buf.buf32[buf->head]; + header = (struct ring_element *) &buf->buf.buf32[mod(buf, buf->head)]; if (header->length > *size32) { *size32 = header->length; @@ -82,15 +142,17 @@ int ring_buf_item_get(struct ring_buf *buf, uint16_t *type, uint8_t *value, index = (i + buf->head + 1) & buf->mask; data[i] = buf->buf.buf32[index]; } - buf->head = (buf->head + header->length + 1) & buf->mask; } else { for (i = 0U; i < header->length; ++i) { index = (i + buf->head + 1) % buf->size; data[i] = buf->buf.buf32[index]; } - buf->head = (buf->head + header->length + 1) % buf->size; } + buf->head = buf->head + header->length + 1; + + item_indexes_rewind(buf); + return 0; } @@ -108,32 +170,34 @@ static inline uint32_t wrap(uint32_t val, uint32_t max) uint32_t ring_buf_put_claim(struct ring_buf *buf, uint8_t **data, uint32_t size) { - uint32_t space, trail_size, allocated; + uint32_t space, trail_size, allocated, tmp_trail_mod; - space = z_ring_buf_custom_space_get(buf->size, buf->head, - buf->misc.byte_mode.tmp_tail); + tmp_trail_mod = mod(buf, buf->misc.byte_mode.tmp_tail); + space = (buf->head + buf->size) - buf->misc.byte_mode.tmp_tail; + trail_size = buf->size - tmp_trail_mod; /* Limit requested size to available size. */ size = MIN(size, space); - trail_size = buf->size - buf->misc.byte_mode.tmp_tail; + + trail_size = buf->size - (tmp_trail_mod); /* Limit allocated size to trail size. */ allocated = MIN(trail_size, size); + *data = &buf->buf.buf8[tmp_trail_mod]; - *data = &buf->buf.buf8[buf->misc.byte_mode.tmp_tail]; buf->misc.byte_mode.tmp_tail = - wrap(buf->misc.byte_mode.tmp_tail + allocated, buf->size); + buf->misc.byte_mode.tmp_tail + allocated; return allocated; } int ring_buf_put_finish(struct ring_buf *buf, uint32_t size) { - if (size > ring_buf_space_get(buf)) { + if ((buf->tail + size) > (buf->head + buf->size)) { return -EINVAL; } - buf->tail = wrap(buf->tail + size, buf->size); + buf->tail += size; buf->misc.byte_mode.tmp_tail = buf->tail; return 0; @@ -162,13 +226,11 @@ uint32_t ring_buf_put(struct ring_buf *buf, const uint8_t *data, uint32_t size) uint32_t ring_buf_get_claim(struct ring_buf *buf, uint8_t **data, uint32_t size) { - uint32_t space, granted_size, trail_size; + uint32_t space, granted_size, trail_size, tmp_head_mod; - space = (buf->size - 1) - - z_ring_buf_custom_space_get(buf->size, - buf->misc.byte_mode.tmp_head, - buf->tail); - trail_size = buf->size - buf->misc.byte_mode.tmp_head; + tmp_head_mod = mod(buf, buf->misc.byte_mode.tmp_head); + space = buf->tail - buf->misc.byte_mode.tmp_head; + trail_size = buf->size - tmp_head_mod; /* Limit requested size to available size. */ granted_size = MIN(size, space); @@ -176,24 +238,23 @@ uint32_t ring_buf_get_claim(struct ring_buf *buf, uint8_t **data, uint32_t size) /* Limit allocated size to trail size. */ granted_size = MIN(trail_size, granted_size); - *data = &buf->buf.buf8[buf->misc.byte_mode.tmp_head]; - buf->misc.byte_mode.tmp_head = - wrap(buf->misc.byte_mode.tmp_head + granted_size, buf->size); + *data = &buf->buf.buf8[tmp_head_mod]; + buf->misc.byte_mode.tmp_head += granted_size; return granted_size; } int ring_buf_get_finish(struct ring_buf *buf, uint32_t size) { - uint32_t allocated = (buf->size - 1) - ring_buf_space_get(buf); - - if (size > allocated) { + if ((buf->head + size) > buf->tail) { return -EINVAL; } - buf->head = wrap(buf->head + size, buf->size); + buf->head += size; buf->misc.byte_mode.tmp_head = buf->head; + byte_indexes_rewind(buf); + return 0; } diff --git a/tests/lib/ringbuffer/Kconfig b/tests/lib/ringbuffer/Kconfig new file mode 100644 index 00000000000..a81abcea7ec --- /dev/null +++ b/tests/lib/ringbuffer/Kconfig @@ -0,0 +1,8 @@ +# Copyright (c) 2020 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config RING_BUFFER_TEST + bool + default y + +source "Kconfig.zephyr" diff --git a/tests/lib/ringbuffer/src/main.c b/tests/lib/ringbuffer/src/main.c index f6e008b0865..4bbfc8e3058 100644 --- a/tests/lib/ringbuffer/src/main.c +++ b/tests/lib/ringbuffer/src/main.c @@ -21,6 +21,17 @@ #include LOG_MODULE_REGISTER(test); +/* Max size is used internally in algorithm. Value is decreased in the test to + * trigger rewind algorithm. + */ +#undef RING_BUFFER_MAX_SIZE +#define RING_BUFFER_MAX_SIZE 0x00000200 + +uint32_t ring_buf_get_rewind_threshold(void) +{ + return RING_BUFFER_MAX_SIZE; +} + /** * @defgroup lib_ringbuffer_tests Ringbuffer * @ingroup all_tests @@ -204,19 +215,19 @@ void test_ringbuffer_init(void) /**TESTPOINT: init via ring_buf_init*/ ring_buf_init(&ringbuf, RINGBUFFER_SIZE, buffer); zassert_true(ring_buf_is_empty(&ringbuf), NULL); - zassert_equal(ring_buf_space_get(&ringbuf), RINGBUFFER_SIZE - 1, NULL); + zassert_equal(ring_buf_space_get(&ringbuf), RINGBUFFER_SIZE, NULL); } void test_ringbuffer_declare_pow2(void) { zassert_true(ring_buf_is_empty(&ringbuf_pow2), NULL); - zassert_equal(ring_buf_space_get(&ringbuf_pow2), (1 << POW) - 1, NULL); + zassert_equal(ring_buf_space_get(&ringbuf_pow2), (1 << POW), NULL); } void test_ringbuffer_declare_size(void) { zassert_true(ring_buf_is_empty(&ringbuf_size), NULL); - zassert_equal(ring_buf_space_get(&ringbuf_size), RINGBUFFER_SIZE - 1, + zassert_equal(ring_buf_space_get(&ringbuf_size), RINGBUFFER_SIZE, NULL); } @@ -263,14 +274,16 @@ void test_ringbuffer_declare_size(void) void test_ringbuffer_put_get_thread(void) { pbuf = &ringbuf; - tringbuf_put((const void *)0); - tringbuf_put((const void *)1); - tringbuf_get((const void *)0); - tringbuf_get((const void *)1); - tringbuf_put((const void *)2); - zassert_false(ring_buf_is_empty(pbuf), NULL); - tringbuf_get((const void *)2); - zassert_true(ring_buf_is_empty(pbuf), NULL); + for (int i = 0; i < 1000; i++) { + tringbuf_put((const void *)0); + tringbuf_put((const void *)1); + tringbuf_get((const void *)0); + tringbuf_get((const void *)1); + tringbuf_put((const void *)2); + zassert_false(ring_buf_is_empty(pbuf), NULL); + tringbuf_get((const void *)2); + zassert_true(ring_buf_is_empty(pbuf), NULL); + } } void test_ringbuffer_put_get_isr(void) @@ -478,7 +491,7 @@ void test_ringbuffer_raw(void) memset(outbuf, 0, sizeof(outbuf)); in_size = ring_buf_put(&ringbuf_raw, inbuf, RINGBUFFER_SIZE); - zassert_equal(in_size, RINGBUFFER_SIZE - 1, NULL); + zassert_equal(in_size, RINGBUFFER_SIZE, NULL); in_size = ring_buf_put(&ringbuf_raw, inbuf, 1); @@ -487,7 +500,7 @@ void test_ringbuffer_raw(void) out_size = ring_buf_get(&ringbuf_raw, outbuf, RINGBUFFER_SIZE); - zassert_true(out_size == RINGBUFFER_SIZE - 1, NULL); + zassert_true(out_size == RINGBUFFER_SIZE, NULL); out_size = ring_buf_get(&ringbuf_raw, outbuf, RINGBUFFER_SIZE + 1); @@ -514,21 +527,21 @@ void test_ringbuffer_alloc_put(void) allocated = ring_buf_put_claim(&ringbuf_raw, &data, RINGBUFFER_SIZE - 1); sum_allocated += allocated; - zassert_true(allocated == RINGBUFFER_SIZE - 2, NULL); + zassert_true(allocated == RINGBUFFER_SIZE - 1, NULL); /* Putting too much returns error */ - err = ring_buf_put_finish(&ringbuf_raw, RINGBUFFER_SIZE); + err = ring_buf_put_finish(&ringbuf_raw, RINGBUFFER_SIZE + 1); zassert_true(err != 0, NULL); err = ring_buf_put_finish(&ringbuf_raw, 1); zassert_true(err == 0, NULL); - err = ring_buf_put_finish(&ringbuf_raw, RINGBUFFER_SIZE - 2); + err = ring_buf_put_finish(&ringbuf_raw, RINGBUFFER_SIZE - 1); zassert_true(err == 0, NULL); read_size = ring_buf_get(&ringbuf_raw, outputbuf, - RINGBUFFER_SIZE - 1); - zassert_true(read_size == (RINGBUFFER_SIZE - 1), NULL); + RINGBUFFER_SIZE); + zassert_true(read_size == RINGBUFFER_SIZE, NULL); for (int i = 0; i < 10; i++) { allocated = ring_buf_put_claim(&ringbuf_raw, &data, 2); @@ -619,7 +632,7 @@ void test_capacity(void) * 1 byte is used for distinguishing between full and empty state. */ capacity = ring_buf_capacity_get(&ringbuf_raw); - zassert_equal(RINGBUFFER_SIZE - 1, capacity, + zassert_equal(RINGBUFFER_SIZE, capacity, "Unexpected capacity"); } @@ -643,18 +656,18 @@ void test_reset(void) zassert_equal(out_len, len, NULL); space = ring_buf_space_get(&ringbuf_raw); - zassert_equal(space, RINGBUFFER_SIZE - 1, NULL); + zassert_equal(space, RINGBUFFER_SIZE, NULL); /* Even though ringbuffer is empty, full buffer cannot be allocated * because internal pointers are not at the beginning. */ granted = ring_buf_put_claim(&ringbuf_raw, &outbuf, RINGBUFFER_SIZE); - zassert_false(granted == RINGBUFFER_SIZE - 1, NULL); + zassert_false(granted == RINGBUFFER_SIZE, NULL); /* After reset full buffer can be allocated. */ ring_buf_reset(&ringbuf_raw); granted = ring_buf_put_claim(&ringbuf_raw, &outbuf, RINGBUFFER_SIZE); - zassert_true(granted == RINGBUFFER_SIZE - 1, NULL); + zassert_true(granted == RINGBUFFER_SIZE, NULL); } #ifdef CONFIG_64BIT @@ -739,27 +752,118 @@ void test_ringbuffer_array_perf(void) zassert_equal(sizeof(tp), sizeof(ringbuf_stored[0]), NULL); } +void test_ringbuffer_partial_putting(void) +{ + uint8_t indata[RINGBUFFER_SIZE]; + uint8_t outdata[RINGBUFFER_SIZE]; + uint32_t len; + uint32_t len2; + uint32_t req_len; + uint8_t *ptr; + + ring_buf_reset(&ringbuf_raw); + + for (int i = 0; i < 100; i++) { + req_len = (i % RINGBUFFER_SIZE) + 1; + len = ring_buf_put(&ringbuf_raw, indata, req_len); + zassert_equal(req_len, len, NULL); + + len = ring_buf_get(&ringbuf_raw, outdata, req_len); + zassert_equal(req_len, len, NULL); + + req_len = 2; + len = ring_buf_put_claim(&ringbuf_raw, &ptr, 2); + zassert_equal(len, 2, NULL); + + len = ring_buf_put_claim(&ringbuf_raw, &ptr, RINGBUFFER_SIZE); + len2 = ring_buf_put_claim(&ringbuf_raw, &ptr, RINGBUFFER_SIZE); + zassert_equal(len + len2, RINGBUFFER_SIZE - 2, NULL); + + ring_buf_put_finish(&ringbuf_raw, RINGBUFFER_SIZE); + + req_len = RINGBUFFER_SIZE; + len = ring_buf_get(&ringbuf_raw, indata, req_len); + zassert_equal(len, req_len, NULL); + } +} + +void test_ringbuffer_partial_getting(void) +{ + uint8_t indata[RINGBUFFER_SIZE]; + uint8_t outdata[RINGBUFFER_SIZE]; + uint32_t len; + uint32_t len2; + uint32_t req_len; + uint8_t *ptr; + + ring_buf_reset(&ringbuf_raw); + + for (int i = 0; i < 100; i++) { + req_len = (i % RINGBUFFER_SIZE) + 1; + len = ring_buf_put(&ringbuf_raw, indata, req_len); + zassert_equal(req_len, len, NULL); + + len = ring_buf_get(&ringbuf_raw, outdata, req_len); + zassert_equal(req_len, len, NULL); + + req_len = sizeof(indata); + len = ring_buf_put(&ringbuf_raw, indata, req_len); + zassert_equal(req_len, len, NULL); + + len = ring_buf_get_claim(&ringbuf_raw, &ptr, 2); + zassert_equal(len, 2, NULL); + + len = ring_buf_get_claim(&ringbuf_raw, &ptr, RINGBUFFER_SIZE); + len2 = ring_buf_get_claim(&ringbuf_raw, &ptr, RINGBUFFER_SIZE); + zassert_equal(len + len2, RINGBUFFER_SIZE - 2, NULL); + + ring_buf_get_finish(&ringbuf_raw, RINGBUFFER_SIZE); + } +} + +void test_ringbuffer_equal_bufs(void) +{ + struct ring_buf buf_ii; + uint8_t *data; + uint32_t claimed; + uint8_t buf[8]; + size_t halfsize = sizeof(buf)/2; + + ring_buf_init(&buf_ii, sizeof(buf), buf); + + for (int i = 0; i < 100; i++) { + claimed = ring_buf_put_claim(&buf_ii, &data, halfsize); + zassert_equal(claimed, halfsize, NULL); + ring_buf_put_finish(&buf_ii, claimed); + + claimed = ring_buf_get_claim(&buf_ii, &data, halfsize); + zassert_equal(claimed, halfsize, NULL); + ring_buf_get_finish(&buf_ii, claimed); + } +} /*test case main entry*/ void test_main(void) { ztest_test_suite(test_ringbuffer_api, - ztest_unit_test(test_ringbuffer_init),/*keep init first!*/ - ztest_unit_test(test_ringbuffer_declare_pow2), - ztest_unit_test(test_ringbuffer_declare_size), - ztest_unit_test(test_ringbuffer_put_get_thread), - ztest_unit_test(test_ringbuffer_put_get_isr), - ztest_unit_test(test_ringbuffer_put_get_thread_isr), - ztest_unit_test(test_ringbuffer_pow2_put_get_thread_isr), - ztest_unit_test(test_ringbuffer_size_put_get_thread_isr), - ztest_unit_test(test_ringbuffer_array_perf), - ztest_unit_test(test_ring_buffer_main), - ztest_unit_test(test_ringbuffer_raw), - ztest_unit_test(test_ringbuffer_alloc_put), - ztest_unit_test(test_byte_put_free), - ztest_unit_test(test_byte_put_free), - ztest_unit_test(test_capacity), - ztest_unit_test(test_reset) - ); + ztest_unit_test(test_ringbuffer_init),/*keep init first!*/ + ztest_unit_test(test_ringbuffer_declare_pow2), + ztest_unit_test(test_ringbuffer_declare_size), + ztest_unit_test(test_ringbuffer_put_get_thread), + ztest_unit_test(test_ringbuffer_put_get_isr), + ztest_unit_test(test_ringbuffer_put_get_thread_isr), + ztest_unit_test(test_ringbuffer_pow2_put_get_thread_isr), + ztest_unit_test(test_ringbuffer_size_put_get_thread_isr), + ztest_unit_test(test_ringbuffer_array_perf), + ztest_unit_test(test_ringbuffer_partial_putting), + ztest_unit_test(test_ringbuffer_partial_getting), + ztest_unit_test(test_ring_buffer_main), + ztest_unit_test(test_ringbuffer_raw), + ztest_unit_test(test_ringbuffer_alloc_put), + ztest_unit_test(test_byte_put_free), + ztest_unit_test(test_ringbuffer_equal_bufs), + ztest_unit_test(test_capacity), + ztest_unit_test(test_reset) + ); ztest_run_test_suite(test_ringbuffer_api); }