Bootstrap

RT-Thread源码阅读之ringbuffer

前言

  1. 为了方便阅读和调试单独抽离源文件
  2. 通过clion进行学习和分析

相关结构体

结构体

struct rt_ringbuffer {
    rt_uint8_t *buffer_ptr; // 数据存放
    rt_uint16_t read_mirror: 1;  // 用于区分缓冲区状态
    rt_uint16_t read_index: 15; // 读数据索引位置
    rt_uint16_t write_mirror: 1; // 用于区分缓冲区状态
    rt_uint16_t write_index: 15; // 写数据索引位置
    rt_int16_t buffer_size; // 数据空间大小
};

枚举

enum rt_ringbuffer_state {
    RT_RINGBUFFER_EMPTY, // 缓冲区为空
    RT_RINGBUFFER_FULL, // 缓冲已满
    RT_RINGBUFFER_HALFFULL, // 缓冲区(未满
};

相关函数

rt_ringbuffer_status(内联函数)

/**
 *
 * @param rb 环形缓冲区结构体
 * @return 缓冲区状态
 *          RT_RINGBUFFER_EMPTY: 缓冲区为空
 *          RT_RINGBUFFER_FULL: 缓冲区满了
 *          RT_RINGBUFFER_HALFFULL: 缓冲区有数据,但没有满
 */
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)
            return RT_RINGBUFFER_EMPTY;
        else
            return RT_RINGBUFFER_FULL;
    }
    return RT_RINGBUFFER_HALFFULL;
}

rt_ringbuffer_data_len

声明

rt_size_t rt_ringbuffer_data_len(struct rt_ringbuffer *rb)

定义

/**
 * 获取环形缓冲区数据长度
 * @param rb 环形缓冲区
 * @return 环形缓冲区数据长度
 */
rt_size_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); // 理解为总长-读取的索引+写的索引(覆盖的数量)
    };
}

rt_ringbuffer_space_len (宏定义)

返回循环缓冲的空余空间大小

#define rt_ringbuffer_space_len(rb) ((rb)->buffer_size - rt_ringbuffer_data_len(rb))

rt_ringbuffer_init

声明

void rt_ringbuffer_init(struct rt_ringbuffer *rb, rt_uint8_t *pool, rt_int16_t size);

定义

/**
 *
 * @param rb 环形缓冲区结构体
 * @param pool 缓冲区指针
 * @param size pool 大小
 */
void rt_ringbuffer_init(struct rt_ringbuffer *rb,
                        rt_uint8_t *pool,
                        rt_int16_t size) {
    // 参数校验
    RT_ASSERT(rb != RT_NULL); // 检验结构体是否为空
    RT_ASSERT(size > 0);     //  检验缓冲区大小是否大于0

    // 初始化读写索引和读写标志位->0
    rb->read_mirror = rb->read_index = 0;
    rb->write_mirror = rb->write_index = 0;

    // 数据指针指向pool
    rb->buffer_ptr = pool;
    // 根据数据对齐返回对应的缓冲区大小,可能使用的空间会比size下
    // 关系为 rb->buffer_size <= size
    rb->buffer_size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
}

rt_ringbuffer_put

声明

rt_size_t rt_ringbuffer_put(struct rt_ringbuffer *rb, const rt_uint8_t *ptr, rt_uint16_t length) 

定义

/**
 * 通过此方法说明,当缓冲数据满的情况,想往里面写入数据是直接丢弃数据
 * @param rb 环形缓冲区结构体
 * @param ptr 写入数据
 * @param length 写入长度
 * @return 返回写入成功的长度; 一般可以与length进行对比,判断是否写入成功
 */
rt_size_t rt_ringbuffer_put(struct rt_ringbuffer *rb, const rt_uint8_t *ptr, rt_uint16_t length) {
    rt_uint16_t size;
    // 环形缓冲区结构体不为空验证
    RT_ASSERT(rb != RT_NULL);
    /* 获取剩余空闲空间大小 */
    size = rt_ringbuffer_space_len(rb);

    /* 没有空间,直接返回 */
    if (size == 0)
        return 0;

    // 剩余空间,不足,将写入的长度改为剩余空间的长度
    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 */
        // 写入索引长度增加length
        rb->write_index += length;
        return length;
    }
    // 出现覆盖已经读取数据区域的情况
    // 01 现将空余的地方进行写入
    memcpy(&rb->buffer_ptr[rb->write_index],&ptr[0],rb->buffer_size - rb->write_index);
    // 02 再将已经读取过数据的地方进行覆盖写入
    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 */
    // 03 写入的位置,从头开始,将标志位取反
    rb->write_mirror = ~rb->write_mirror;
    // 04 更新写入位置
    rb->write_index = length - (rb->buffer_size - rb->write_index);

    return length;
}

rt_ringbuffer_put_force

1、此函数rt_ringbuffer_put不同的地方就是,会覆盖原有的数据,保持新数据能添加

声明

rt_size_t rt_ringbuffer_put_force(struct rt_ringbuffer *rb,const rt_uint8_t *ptr,rt_uint16_t length) 

定义

/**
 * 通过此方法说明,当缓冲数据满的情况,会覆盖原有的数据
 * @param rb 环形缓冲区结构体
 * @param ptr 写入数据
 * @param length 写入的长度;
 * @return 
 */
rt_size_t rt_ringbuffer_put_force(struct rt_ringbuffer *rb,const rt_uint8_t *ptr,rt_uint16_t length) {
    rt_uint16_t space_length;

    RT_ASSERT(rb != RT_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;
}

rt_ringbuffer_get

声明

rt_size_t rt_ringbuffer_get(struct rt_ringbuffer *rb,rt_uint8_t *ptr,rt_uint16_t length)

定义

/**
 * 从缓冲区获取数据
 * @param rb 
 * @param ptr 
 * @param length 
 * @return 获取的实际长度
 */
rt_size_t rt_ringbuffer_get(struct rt_ringbuffer *rb,rt_uint8_t *ptr,rt_uint16_t length) {
    rt_size_t size;

    RT_ASSERT(rb != RT_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;
}

剩余函数

都比较简单,请自行查看RT-Thread源码

;