嵌入式ringbuf精妙设计

ringbuf数据结构:

typedef struct quec_ring_buf_struct {
    unsigned int size;
    unsigned int  rpos;
    unsigned int  wpos;
    unsigned char *data;
}quec_ring_buf_t;
  • rpos,指向待读取数据的起始位置
  • wpos,指向下一个可写入数据的位置
  • data,存储数据的内存空间,
  • size,环形buf大小,大小常设为2的幂以优化取模运算

读写机制

  • 写入数据:数据从wpos位置插入,wpos递增(以32位unsigned int为例,超过4294967295则 回绕到0),但要保证wpos-rpos要小于size。否则旧数据被覆盖丢失
  • 读取数据:数据从rpos位置取出,rpos递增(以32位unsigned int为例,超过4294967295则 回绕到0)
  • 关键逻辑:通过rpos、wpos索引形成环形

如何理解这个ringbuf,举个例子:w和r两个人在环形操场上跑步,操场长度为4294967295米,w在前面跑,r在后面追。w和r要遵守两个规则,w不能领先r size的长度,r不能超越w.

他们俩就这样一直跑着跑着,像CPU一样永不停歇.....

代码实现实例

创建

quec_ring_buf_t *__kfifo_rb_create(unsigned int size)
{
	quec_ring_buf_t *rb = NULL;
	
	if (size <= 0) {
		return NULL;
	}
	rb = malloc(sizeof(quec_ring_buf_t));
	if (NULL == rb) {
		return NULL;
	}
	memset(rb, 0, sizeof(quec_ring_buf_t));
	
	rb->data = malloc(size);
	memset(rb->data, 0, size);
	if (NULL == rb->data) {
		free(rb);
		return NULL;
	}
	rb->size = size;
	return rb;
}

销毁

void __kfifo_rb_destroy(quec_ring_buf_t **rb)
{
	if (*rb) {
        if ((*rb)->data) {
        free((*rb)->data);
        (*rb)->data = NULL;
        }
        free(*rb);
        *rb = NULL;
	}
}

 读操作

unsigned int __kfifo_rb_read(quec_ring_buf_t *rb, unsigned char *data, unsigned int len)
{
	unsigned int r_size = 0, r_free_size = 0;
	unsigned int r_data_len = 0;
	
	if (!rb || !data || (len <= 0)) {
        //quec_log("%s,rb=%#x,data=%#x,len=%d",__func__,rb,data,len);
		return 0;
	}
    /*以下操作rb禁止被抢占,否则会导致其他任务获取的读写指针不是实时的,所以这里暂时将抢占优先级抬到0*/
    quec_rtos_task_sched_lock();
	r_data_len = __kfifo_rb_data_len(rb);
	r_size = len < r_data_len ? len : r_data_len;
	
	/* first get the data from ring_buf->read_pos until the end of the buffer */
	r_free_size = r_size < (rb->size-(rb->rpos&(rb->size-1))) ? r_size : (rb->size-(rb->rpos&(rb->size-1)));
	
	memcpy(data, rb->data+(rb->rpos&(rb->size-1)), r_free_size);
	/* then get the rest (if any) from the beginning of the buffer */
	memcpy(data+r_free_size, rb->data, r_size-r_free_size);

	rb->rpos += r_size;
    quec_rtos_task_sched_unlock();
    
	return r_size;
}

写操作

unsigned int __kfifo_rb_write(quec_ring_buf_t *rb, unsigned char *data, unsigned int len)
{
	unsigned int w_size = 0, w_free_size = 0;
	unsigned int r_free_size = 0;

	if (!rb || !data || (len <= 0)) {
        //quec_log("%s,rb=%#x,data=%#x,len=%d",__func__,rb,data,len);
		return 0;
	}
    /*以下操作rb禁止被抢占,否则会导致其他任务获取的读写指针不是实时的,所以这里暂时将抢占优先级抬到0*/
    quec_rtos_task_sched_lock();
	r_free_size = __kfifo_rb_free_space(rb);
	w_size = len < r_free_size ? len : r_free_size;
	
	/* first put the data starting from write_pos to buffer end */ 
	w_free_size = w_size < (rb->size-(rb->wpos&(rb->size-1))) ? w_size : (rb->size-(rb->wpos&(rb->size-1)));

	memcpy(rb->data+(rb->wpos&(rb->size-1)), data, w_free_size);
	/* then put the rest (if any) at the beginning of the buffer */ 
	memcpy(rb->data, data+w_free_size, w_size-w_free_size);

	rb->wpos += w_size;
    quec_rtos_task_sched_unlock();

	return w_size;
}

判断状态

  • 空状态
unsigned int __kfifo_rb_is_empty(quec_ring_buf_t *rb)
{
    char ret=0;
	ret = (rb->wpos == rb->rpos);
    return ret;
}
  • 满状态
unsigned int __kfifo_rb_is_full(quec_ring_buf_t *rb)
{
    char ret=0;
	ret=(rb->size == (rb->wpos-rb->rpos));
    return ret;
}
  • 剩余空间
unsigned int __kfifo_rb_free_space(quec_ring_buf_t *rb)
{
    unsigned int len = 0;
	len = rb->size - (rb->wpos - rb->rpos);
    return len;
}
  • 使用空间
unsigned int __kfifo_rb_data_len(quec_ring_buf_t *rb)
{
    unsigned int len = 0;
	len = rb->wpos - rb->rpos;
     return len;
}

上述是ringbuf源码的实现,代码很精简,可以使用在嵌入式系统的方方面面,希望对大家带来帮助 

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值