嵌入式--环形缓冲(1)

嵌入式–环形缓冲(1)

感谢RT-Thread Development Team,这个模块是他们设计出来,很好用,一直用到现在,之所以取名为环形缓冲(1),还有一个取自于linux的环形缓冲,在下一篇文件粘贴出来,感谢大佬们。

头文件 ringbuffer.h

/*

 * Copyright (c) 2006-2018, RT-Thread Development Team
    *
 * SPDX-License-Identifier: Apache-2.0
    *
 * Change Logs:
 * Date           Author       Notes
    */
    #ifndef RINGBUFFER_H__
    #define RINGBUFFER_H__

#ifdef __cplusplus
extern "C" {
#endif

#include "stdint.h"
#include "stdio.h"
#include "string.h"

#define RTM_EXPORT(symbol)

#define RT_ASSERT(EX)                                                         \
//if (!(EX))                                                                    \
//{                                                                             \
//    printf("(%s) assertion failed at function:%s, line number:%d \n",#EX, __FUNCTION__, __LINE__);                           \
//}

#define RT_ALIGN_DOWN(size, align)      ((size) & ~((align) - 1))
#define RT_ALIGN_SIZE 4

/* ring buffer */
struct rt_ringbuffer
{
    uint8_t *buffer_ptr;
    /* use the msb of the {read,write}_index as mirror bit. You can see this as
     * if the buffer adds a virtual mirror and the pointers point either to the
     * normal or to the mirrored buffer. If the write_index has the same value
     * with the read_index, but in a different mirror, the buffer is full.
     * While if the write_index and the read_index are the same and within the
     * same mirror, the buffer is empty. The ASCII art of the ringbuffer is:
     *
     *          mirror = 0                    mirror = 1
     * +---+---+---+---+---+---+---+|+~~~+~~~+~~~+~~~+~~~+~~~+~~~+
     * | 0 | 1 | 2 | 3 | 4 | 5 | 6 ||| 0 | 1 | 2 | 3 | 4 | 5 | 6 | Full
     * +---+---+---+---+---+---+---+|+~~~+~~~+~~~+~~~+~~~+~~~+~~~+
     *  read_idx-^                   write_idx-^
     *
     * +---+---+---+---+---+---+---+|+~~~+~~~+~~~+~~~+~~~+~~~+~~~+
     * | 0 | 1 | 2 | 3 | 4 | 5 | 6 ||| 0 | 1 | 2 | 3 | 4 | 5 | 6 | Empty
     * +---+---+---+---+---+---+---+|+~~~+~~~+~~~+~~~+~~~+~~~+~~~+
     * read_idx-^ ^-write_idx
     *
     * The tradeoff is we could only use 32KiB of buffer for 16 bit of index.
     * But it should be enough for most of the cases.
     *
     * Ref: http://en.wikipedia.org/wiki/Circular_buffer#Mirroring */
    uint16_t read_mirror : 1;
    uint16_t read_index : 15;
    uint16_t write_mirror : 1;
    uint16_t write_index : 15;
    /* as we use msb of index as mirror bit, the size should be signed and
     * could only be positive. */
    uint16_t buffer_size;
};

enum rt_ringbuffer_state
{
    RT_RINGBUFFER_EMPTY,
    RT_RINGBUFFER_FULL,
    /* half full is neither full nor empty */
    RT_RINGBUFFER_HALFFULL,
};

/**
 * RingBuffer for DeviceDriver
    *
 * Please note that the ring buffer implementation of RT-Thread
 * has no thread wait or resume feature.
    */
    void rt_ringbuffer_init(struct rt_ringbuffer *rb, uint8_t *pool, uint16_t size);
    void rt_ringbuffer_reset(struct rt_ringbuffer *rb);
    unsigned long rt_ringbuffer_put(struct rt_ringbuffer *rb, const uint8_t *ptr, uint16_t length);
    unsigned long rt_ringbuffer_put_force(struct rt_ringbuffer *rb, const uint8_t *ptr, uint16_t length);
    unsigned long rt_ringbuffer_putchar(struct rt_ringbuffer *rb, const uint8_t ch);
    unsigned long rt_ringbuffer_putchar_force(struct rt_ringbuffer *rb, const uint8_t ch);
    unsigned long rt_ringbuffer_get(struct rt_ringbuffer *rb, uint8_t *ptr, uint16_t length);
    unsigned long rt_ringbuffer_getchar(struct rt_ringbuffer *rb, uint8_t *ch);
    unsigned long rt_ringbuffer_data_len(struct rt_ringbuffer *rb);

static __inline uint16_t rt_ringbuffer_get_size(struct rt_ringbuffer *rb)
{
    RT_ASSERT(rb != NULL);
    return rb->buffer_size;
}

/** return the size of empty space in rb */
#define rt_ringbuffer_space_len(rb) ((rb)->buffer_size - rt_ringbuffer_data_len(rb))


#ifdef __cplusplus
}
#endif

#endif

源文件 ringbuffer.c

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#include "ringbuffer.h"

static __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)
            return RT_RINGBUFFER_EMPTY;
        else
            return RT_RINGBUFFER_FULL;
    }
    return RT_RINGBUFFER_HALFFULL;
}

void rt_ringbuffer_init(struct rt_ringbuffer *rb,
                        uint8_t           *pool,
                        uint16_t            size)
{
    RT_ASSERT(rb != NULL);
    RT_ASSERT(size > 0);

    /* initialize read and write index */
    rb->read_mirror = rb->read_index = 0;
    rb->write_mirror = rb->write_index = 0;
    
    /* set buffer pool and size */
    rb->buffer_ptr = pool;
    rb->buffer_size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
}
RTM_EXPORT(rt_ringbuffer_init);

/**
 * put a block of data into ring buffer
    */
    unsigned long rt_ringbuffer_put(struct rt_ringbuffer *rb,
                            const uint8_t     *ptr,
                            uint16_t           length)
    {
    uint16_t size;

    RT_ASSERT(rb != NULL);

    /* whether has enough space */
    size = rt_ringbuffer_space_len(rb);

    /* no space */
    if (size == 0)
        return 0;

    /* drop some data */
    if (size < length)
        length = 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;
        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);

    return length;
    }
    RTM_EXPORT(rt_ringbuffer_put);

/**
 * put a block of data into ring buffer
    *
 * When the buffer is full, it will discard the old data.
    */
    unsigned long rt_ringbuffer_put_force(struct rt_ringbuffer *rb,
                            const uint8_t     *ptr,
                            uint16_t           length)
    {
    uint16_t space_length;

    RT_ASSERT(rb != NULL);

    space_length = rt_ringbuffer_space_len(rb);

    if (length > rb->buffer_size)
    {
        ptr = &ptr[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 (length > space_length)
            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 (length > space_length)
    {
        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
     */
     unsigned long rt_ringbuffer_get(struct rt_ringbuffer *rb,
                            uint8_t           *ptr,
                            uint16_t           length)
     {
    unsigned long size;
    
    RT_ASSERT(rb != NULL);
    
    /* whether has enough data  */
    size = rt_ringbuffer_data_len(rb);
    
    /* no data */
    if (size == 0)
        return 0;
    
    /* less data */
    if (size < length)
        length = size;
    
    if (rb->buffer_size - rb->read_index > length)
    {
        /* copy all of data */
        memcpy(ptr, &rb->buffer_ptr[rb->read_index], length);
        /* this should not cause overflow because there is enough space for
         * length of data in current mirror */
        rb->read_index += length;
        return length;
    }
    
    memcpy(&ptr[0],
           &rb->buffer_ptr[rb->read_index],
           rb->buffer_size - rb->read_index);
    memcpy(&ptr[rb->buffer_size - rb->read_index],
           &rb->buffer_ptr[0],
           length - (rb->buffer_size - rb->read_index));
    
    /* we are going into the other side of the mirror */
    rb->read_mirror = ~rb->read_mirror;
    rb->read_index = length - (rb->buffer_size - rb->read_index);
    
    return length;
}
RTM_EXPORT(rt_ringbuffer_get);

/**
 * put a character into ring buffer
    */
    unsigned long rt_ringbuffer_putchar(struct rt_ringbuffer *rb, const uint8_t ch)
    {
    RT_ASSERT(rb != NULL);

    /* whether has enough space */
    if (!rt_ringbuffer_space_len(rb))
        return 0;

    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;
    }
    else
    {
        rb->write_index++;
    }

    return 1;
    }
    RTM_EXPORT(rt_ringbuffer_putchar);

/**
 * put a character into ring buffer
    *
 * When the buffer is full, it will discard one old data.
    */
    unsigned long rt_ringbuffer_putchar_force(struct rt_ringbuffer *rb, const uint8_t ch)
    {
    enum rt_ringbuffer_state old_state;

    RT_ASSERT(rb != 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
    */
    unsigned long rt_ringbuffer_getchar(struct rt_ringbuffer *rb, uint8_t *ch)
    {
    RT_ASSERT(rb != NULL);

    /* ringbuffer is empty */
    if (!rt_ringbuffer_data_len(rb))
        return 0;

    /* put character */
    *ch = rb->buffer_ptr[rb->read_index];

    if (rb->read_index == rb->buffer_size-1)
    {
        rb->read_mirror = ~rb->read_mirror;
        rb->read_index = 0;
    }
    else
    {
        rb->read_index++;
    }

    return 1;
    }
    RTM_EXPORT(rt_ringbuffer_getchar);

/** 
 * get the size of data in rb 
    */
    unsigned long 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);
    };
    }
    RTM_EXPORT(rt_ringbuffer_data_len);

/** 
 * empty the rb 
    */
    void rt_ringbuffer_reset(struct rt_ringbuffer *rb)
    {
    RT_ASSERT(rb != NULL);

    rb->read_mirror = 0;
    rb->read_index = 0;
    rb->write_mirror = 0;
    rb->write_index = 0;
    }
    RTM_EXPORT(rt_ringbuffer_reset);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值