From 4919d29d693491e8eae9697deed7b808c7bcbb93 Mon Sep 17 00:00:00 2001 From: Grissiom Date: Mon, 19 Aug 2013 11:52:04 +0800 Subject: [PATCH] ringbuffer: add put_force and putchar_force API Add the APIs that will discard the old data when rb is full. --- components/drivers/include/rtdevice.h | 38 +++++++++-- components/drivers/src/ringbuffer.c | 93 +++++++++++++++++++++++++++ 2 files changed, 124 insertions(+), 7 deletions(-) diff --git a/components/drivers/include/rtdevice.h b/components/drivers/include/rtdevice.h index a941b2213..bd6e243b0 100644 --- a/components/drivers/include/rtdevice.h +++ b/components/drivers/include/rtdevice.h @@ -134,37 +134,61 @@ void rt_ringbuffer_init(struct rt_ringbuffer *rb, rt_size_t rt_ringbuffer_put(struct rt_ringbuffer *rb, const rt_uint8_t *ptr, rt_uint16_t length); +rt_size_t rt_ringbuffer_put_force(struct rt_ringbuffer *rb, + const rt_uint8_t *ptr, + rt_uint16_t length); rt_size_t rt_ringbuffer_putchar(struct rt_ringbuffer *rb, const rt_uint8_t ch); +rt_size_t rt_ringbuffer_putchar_force(struct rt_ringbuffer *rb, + const rt_uint8_t ch); rt_size_t rt_ringbuffer_get(struct rt_ringbuffer *rb, rt_uint8_t *ptr, rt_uint16_t length); rt_size_t rt_ringbuffer_getchar(struct rt_ringbuffer *rb, rt_uint8_t *ch); +enum rt_ringbuffer_state +{ + RT_RINGBUFFER_EMPTY, + RT_RINGBUFFER_FULL, + /* half full is neither full nor empty */ + RT_RINGBUFFER_HALFFULL, +}; + rt_inline rt_uint16_t rt_ringbuffer_get_size(struct rt_ringbuffer *rb) { RT_ASSERT(rb != RT_NULL); return rb->buffer_size; } -/** return the size of data in rb */ -rt_inline rt_uint16_t rt_ringbuffer_data_len(struct rt_ringbuffer *rb) +rt_inline enum rt_ringbuffer_state +rt_ringbuffer_status(struct rt_ringbuffer *rb) { if (rb->read_index == rb->write_index) { if (rb->read_mirror == rb->write_mirror) - /* we are in the same side, the ringbuffer is empty. */ - return 0; + return RT_RINGBUFFER_EMPTY; else - return rb->buffer_size; + return RT_RINGBUFFER_FULL; } - else + return RT_RINGBUFFER_HALFFULL; +} + +/** return the size of data in rb */ +rt_inline rt_uint16_t rt_ringbuffer_data_len(struct rt_ringbuffer *rb) +{ + switch (rt_ringbuffer_status(rb)) { + case RT_RINGBUFFER_EMPTY: + return 0; + case RT_RINGBUFFER_FULL: + return rb->buffer_size; + case RT_RINGBUFFER_HALFFULL: + default: if (rb->write_index > rb->read_index) return rb->write_index - rb->read_index; else return rb->buffer_size - (rb->read_index - rb->write_index); - } + }; } /** return the size of empty space in rb */ diff --git a/components/drivers/src/ringbuffer.c b/components/drivers/src/ringbuffer.c index ecc258704..6212b1025 100644 --- a/components/drivers/src/ringbuffer.c +++ b/components/drivers/src/ringbuffer.c @@ -44,6 +44,9 @@ void rt_ringbuffer_init(struct rt_ringbuffer *rb, } RTM_EXPORT(rt_ringbuffer_init); +/** + * put a block of data into ring buffer + */ rt_size_t rt_ringbuffer_put(struct rt_ringbuffer *rb, const rt_uint8_t *ptr, rt_uint16_t length) @@ -88,6 +91,59 @@ rt_size_t rt_ringbuffer_put(struct rt_ringbuffer *rb, } RTM_EXPORT(rt_ringbuffer_put); +/** + * put a block of data into ring buffer + * + * When the buffer is full, it will discard the old data. + */ +rt_size_t rt_ringbuffer_put_force(struct rt_ringbuffer *rb, + const rt_uint8_t *ptr, + rt_uint16_t length) +{ + enum rt_ringbuffer_state old_state; + + RT_ASSERT(rb != RT_NULL); + + old_state = rt_ringbuffer_status(rb); + + if (length > rb->buffer_size) + length = rb->buffer_size; + + if (rb->buffer_size - rb->write_index > length) + { + /* read_index - write_index = empty space */ + 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 (old_state == RT_RINGBUFFER_FULL) + rb->read_index = rb->write_index; + + return length; + } + + memcpy(&rb->buffer_ptr[rb->write_index], + &ptr[0], + rb->buffer_size - rb->write_index); + 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); + + if (old_state == RT_RINGBUFFER_FULL) + { + rb->read_mirror = ~rb->read_mirror; + rb->read_index = rb->write_index; + } + + return length; +} +RTM_EXPORT(rt_ringbuffer_put_force); + /** * get data from ring buffer */ @@ -163,6 +219,43 @@ rt_size_t rt_ringbuffer_putchar(struct rt_ringbuffer *rb, const rt_uint8_t ch) } RTM_EXPORT(rt_ringbuffer_putchar); +/** + * put a character into ring buffer + * + * When the buffer is full, it will discard one old data. + */ +rt_size_t rt_ringbuffer_putchar_force(struct rt_ringbuffer *rb, const rt_uint8_t ch) +{ + enum rt_ringbuffer_state old_state; + + RT_ASSERT(rb != RT_NULL); + + old_state = rt_ringbuffer_status(rb); + + rb->buffer_ptr[rb->write_index] = ch; + + /* flip mirror */ + if (rb->write_index == rb->buffer_size-1) + { + rb->write_mirror = ~rb->write_mirror; + rb->write_index = 0; + if (old_state == RT_RINGBUFFER_FULL) + { + rb->read_mirror = ~rb->read_mirror; + rb->read_index = rb->write_index; + } + } + else + { + rb->write_index++; + if (old_state == RT_RINGBUFFER_FULL) + rb->read_index = rb->write_index; + } + + return 1; +} +RTM_EXPORT(rt_ringbuffer_putchar_force); + /** * get a character from a ringbuffer */