浏览代码

ringbuffer: add put_force and putchar_force API

Add the APIs that will discard the old data when rb is full.
Grissiom 11 年之前
父节点
当前提交
4919d29d69
共有 2 个文件被更改,包括 124 次插入7 次删除
  1. 31 7
      components/drivers/include/rtdevice.h
  2. 93 0
      components/drivers/src/ringbuffer.c

+ 31 - 7
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 */

+ 93 - 0
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
  */