Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 66 additions & 31 deletions components/drivers/ipc/ringbuffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
* 2016-08-18 heyuanjie add interface
* 2021-07-20 arminker fix write_index bug in function rt_ringbuffer_put_force
* 2021-08-14 Jackistang add comments for function interface.
* 2026-03-16 RyanCW(Codex) fix put_force overwrite in wrapped state
*/

#include <rtdevice.h>
Expand All @@ -35,11 +36,12 @@ rt_inline enum rt_ringbuffer_state rt_ringbuffer_status(struct rt_ringbuffer *rb
* @param size The size of the buffer in bytes.
*/
void rt_ringbuffer_init(struct rt_ringbuffer *rb,
rt_uint8_t *pool,
rt_int32_t size)
rt_uint8_t *pool,
rt_int32_t size)
{
RT_ASSERT(rb != RT_NULL);
RT_ASSERT(size > 0);
RT_ASSERT(pool != RT_NULL);
RT_ASSERT(size >= RT_ALIGN_SIZE);

/* initialize read and write index */
rb->read_mirror = rb->read_index = 0;
Expand All @@ -61,12 +63,15 @@ RTM_EXPORT(rt_ringbuffer_init);
* @return Return the data size we put into the ring buffer.
*/
rt_size_t rt_ringbuffer_put(struct rt_ringbuffer *rb,
const rt_uint8_t *ptr,
rt_uint32_t length)
const rt_uint8_t *ptr,
rt_uint32_t length)
{
rt_uint32_t size;

RT_ASSERT(rb != RT_NULL);
if (length == 0)
return 0;
RT_ASSERT(ptr != RT_NULL);

/* whether has enough space */
size = rt_ringbuffer_space_len(rb);
Expand Down Expand Up @@ -114,53 +119,75 @@ RTM_EXPORT(rt_ringbuffer_put);
* @return Return the data size we put into the ring buffer.
*/
rt_size_t rt_ringbuffer_put_force(struct rt_ringbuffer *rb,
const rt_uint8_t *ptr,
rt_uint32_t length)
const rt_uint8_t *ptr,
rt_uint32_t length)
{
rt_uint32_t space_length;
rt_uint32_t drop_length;

RT_ASSERT(rb != RT_NULL);

space_length = rt_ringbuffer_space_len(rb);
if (length == 0)
return 0;
RT_ASSERT(ptr != RT_NULL);

/* Oversize write keeps the latest bytes. */
if (length > rb->buffer_size)
{
ptr = &ptr[length - rb->buffer_size];
length = rb->buffer_size;
}

space_length = rt_ringbuffer_space_len(rb);

rt_bool_t overflow = (length > space_length);

if (overflow)
{
/* Drop the oldest bytes to make room for the incoming data. */
drop_length = length - space_length;
if (rb->buffer_size - rb->read_index > drop_length)
{
rb->read_index += drop_length;
}
else
{
drop_length -= (rb->buffer_size - rb->read_index);
rb->read_index = drop_length;
/* Read pointer wraps to the other side of the mirror. */
rb->read_mirror = ~rb->read_mirror;
}
}

if (rb->buffer_size - rb->write_index > length)
{
/* read_index - write_index = empty space */
rt_memcpy(&rb->buffer_ptr[rb->write_index], ptr, length);
/* this should not cause overflow because there is enough space for
* length of data in current mirror */
rb->write_index += length;

if (length > space_length)
rb->read_index = rb->write_index;

return length;
}
else
{
rt_uint32_t tail = rb->buffer_size - rb->write_index;

rt_memcpy(&rb->buffer_ptr[rb->write_index],
&ptr[0],
rb->buffer_size - rb->write_index);
rt_memcpy(&rb->buffer_ptr[0],
&ptr[rb->buffer_size - rb->write_index],
length - (rb->buffer_size - rb->write_index));

/* we are going into the other side of the mirror */
rb->write_mirror = ~rb->write_mirror;
rb->write_index = length - (rb->buffer_size - rb->write_index);
rt_memcpy(&rb->buffer_ptr[rb->write_index], ptr, tail);
rt_memcpy(&rb->buffer_ptr[0], &ptr[tail], length - tail);

if (length > space_length)
{
if (rb->write_index <= rb->read_index)
rb->read_mirror = ~rb->read_mirror;
rb->read_index = rb->write_index;
/* we are going into the other side of the mirror */
rb->write_mirror = ~rb->write_mirror;
rb->write_index = length - tail;
}

/*
* If we dropped data and write catches up to read, we must keep
* "full" distinct from "empty" by flipping the write mirror.
*/
if (overflow &&
(rb->write_index == rb->read_index) &&
(rb->write_mirror == rb->read_mirror))
rb->write_mirror = ~rb->write_mirror;

return length;
}
RTM_EXPORT(rt_ringbuffer_put_force);
Expand All @@ -175,12 +202,15 @@ RTM_EXPORT(rt_ringbuffer_put_force);
* @return Return the data size we read from the ring buffer.
*/
rt_size_t rt_ringbuffer_get(struct rt_ringbuffer *rb,
rt_uint8_t *ptr,
rt_uint32_t length)
rt_uint8_t *ptr,
rt_uint32_t length)
{
rt_size_t size;

RT_ASSERT(rb != RT_NULL);
if (length == 0)
return 0;
RT_ASSERT(ptr != RT_NULL);

/* whether has enough data */
size = rt_ringbuffer_data_len(rb);
Expand Down Expand Up @@ -235,6 +265,7 @@ rt_size_t rt_ringbuffer_get_direct(struct rt_ringbuffer *rb, rt_uint8_t **ptr)
rt_size_t size;

RT_ASSERT(rb != RT_NULL);
RT_ASSERT(ptr != RT_NULL);

*ptr = RT_NULL;

Expand Down Expand Up @@ -278,6 +309,7 @@ rt_size_t rt_ringbuffer_peek(struct rt_ringbuffer *rb, rt_uint8_t **ptr)
rt_size_t size;

RT_ASSERT(rb != RT_NULL);
RT_ASSERT(ptr != RT_NULL);

*ptr = RT_NULL;

Expand Down Expand Up @@ -386,6 +418,7 @@ RTM_EXPORT(rt_ringbuffer_putchar_force);
rt_size_t rt_ringbuffer_getchar(struct rt_ringbuffer *rb, rt_uint8_t *ch)
{
RT_ASSERT(rb != RT_NULL);
RT_ASSERT(ch != RT_NULL);

/* ringbuffer is empty */
if (!rt_ringbuffer_data_len(rb))
Expand Down Expand Up @@ -417,6 +450,8 @@ RTM_EXPORT(rt_ringbuffer_getchar);
*/
rt_size_t rt_ringbuffer_data_len(struct rt_ringbuffer *rb)
{
RT_ASSERT(rb != RT_NULL);

switch (rt_ringbuffer_status(rb))
{
case RT_RINGBUFFER_EMPTY:
Expand Down Expand Up @@ -467,7 +502,7 @@ struct rt_ringbuffer *rt_ringbuffer_create(rt_uint32_t size)
struct rt_ringbuffer *rb;
rt_uint8_t *pool;

RT_ASSERT(size > 0);
RT_ASSERT(size >= RT_ALIGN_SIZE);

size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);

Expand Down
4 changes: 4 additions & 0 deletions components/drivers/ipc/utest/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,8 @@ config RT_UTEST_WORKQUEUE
bool "IPC Workqueue Test"
default n

config RT_UTEST_RINGBUFFER
bool "IPC Ringbuffer Test"
default n

endmenu
3 changes: 3 additions & 0 deletions components/drivers/ipc/utest/SConscript
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ if GetDepend(['RT_UTEST_COMPLETION']):
if GetDepend(['RT_UTEST_WORKQUEUE']):
src += ['workqueue_tc.c']

if GetDepend(['RT_UTEST_RINGBUFFER']):
src += ['ringbuffer_tc.c']

group = DefineGroup('utestcases', src, depend = ['RT_USING_UTESTCASES'], CPPPATH = CPPPATH)

Return('group')
Loading
Loading