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源码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
由于DW_axi_dmac是一款IP核,其驱动码的具体实现可能会因具体的芯片型号、IP核版本、DMA通道数等因素而有所差异。以下是DW_axi_dmac在rt-thread中的一份示例驱动码供参考: ``` #include <rtthread.h> #include <rtdevice.h> #include <board.h> #include <dw_axi_dmac.h> #define DW_AXI_DMAC_BASEADDR 0x40000000 #define DW_AXI_DMAC_IRQNUM 10 #define DW_AXI_DMAC_CHAN_NUM 8 struct dw_axi_dmac_device { const char *name; rt_uint32_t baseaddr; rt_uint32_t irqnum; rt_uint32_t chan_num; }; struct dw_axi_dmac_device dw_axi_dmac = { .name = "dw_axi_dmac", .baseaddr = DW_AXI_DMAC_BASEADDR, .irqnum = DW_AXI_DMAC_IRQNUM, .chan_num = DW_AXI_DMAC_CHAN_NUM, }; static rt_err_t dw_axi_dmac_init(rt_device_t dev) { /* 初始化DW_axi_dmac硬件 */ dw_axi_dmac_hw_init(dw_axi_dmac.baseaddr, dw_axi_dmac.irqnum, dw_axi_dmac.chan_num); return RT_EOK; } static rt_err_t dw_axi_dmac_open(rt_device_t dev, rt_uint16_t oflag) { /* 打开DW_axi_dmac设备 */ return RT_EOK; } static rt_err_t dw_axi_dmac_close(rt_device_t dev) { /* 关闭DW_axi_dmac设备 */ return RT_EOK; } static rt_size_t dw_axi_dmac_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size) { /* 读取数据 */ return dw_axi_dmac_read_data(dw_axi_dmac.baseaddr, buffer, size); } static rt_size_t dw_axi_dmac_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size) { /* 写入数据 */ return dw_axi_dmac_write_data(dw_axi_dmac.baseaddr, buffer, size); } static rt_err_t dw_axi_dmac_control(rt_device_t dev, int cmd, void *args) { rt_err_t ret = RT_EOK; switch (cmd) { case RT_DEVICE_CTRL_CONFIG: /* 配置DW_axi_dmac设备 */ break; case RT_DEVICE_CTRL_RESET: /* 重置DW_axi_dmac设备 */ break; default: ret = RT_ERROR; break; } return ret; } static struct rt_device dw_axi_dmac_device = { .type = RT_Device_Class_Char, .init = dw_axi_dmac_init, .open = dw_axi_dmac_open, .close = dw_axi_dmac_close, .read = dw_axi_dmac_read, .write = dw_axi_dmac_write, .control = dw_axi_dmac_control, }; int rt_hw_dw_axi_dmac_init(void) { rt_err_t result; result = rt_device_register(&dw_axi_dmac_device, dw_axi_dmac.name, RT_DEVICE_FLAG_RDWR); if (result == RT_EOK) { return 0; } else { return -1; } } ``` 以上代码是DW_axi_dmac在rt-thread中的一份示例驱动码,其中包括初始化函数、打开/关闭函数、读写函数和控制函数等。其中,dw_axi_dmac_hw_init()、dw_axi_dmac_read_data()和dw_axi_dmac_write_data()等函数是DW_axi_dmac的底层驱动函数,需要根据具体的IP核版本和DMA通道数进行实现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

詩不诉卿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值