1、ring_buffer.c
#include "ring_buffer.h"
#include <string.h>
static void ring_buf_internal_reset(struct ring_buf *buf, int32_t value)
{
buf->put_head = buf->put_tail = buf->put_base = value;
buf->get_head = buf->get_tail = buf->get_base = value;
}
static uint32_t ring_buf_size_get(struct ring_buf *buf)
{
return buf->put_tail - buf->get_head;
}
uint32_t ring_buf_space_get(struct ring_buf *buf)
{
return buf->size - (buf->put_head - buf->get_tail);
}
uint32_t ring_buf_put_claim(struct ring_buf *buf, uint8_t **data, uint32_t size)
{
uint32_t free_space, wrap_size;
int32_t base;
base = buf->put_base;
wrap_size = buf->put_head - base;
if (unlikely(wrap_size >= buf->size)) {
/* put_base is not yet adjusted */
wrap_size -= buf->size;
base += buf->size;
}
wrap_size = buf->size - wrap_size;
free_space = ring_buf_space_get(buf);
size = MIN(size, free_space);
size = MIN(size, wrap_size);
*data = &buf->buffer[buf->put_head - base];
buf->put_head += size;
return size;
}
int ring_buf_put_finish(struct ring_buf *buf, uint32_t size)
{
uint32_t finish_space, wrap_size;
finish_space = buf->put_head - buf->put_tail;
if (unlikely(size > finish_space)) {
return -1;
}
buf->put_tail += size;
buf->put_head = buf->put_tail;
wrap_size = buf->put_tail - buf->put_base;
if (unlikely(wrap_size >= buf->size)) {
/* we wrapped: adjust put_base */
buf->put_base += buf->size;
}
return 0;
}
uint32_t ring_buf_get_claim(struct ring_buf *buf, uint8_t **data, uint32_t size)
{
uint32_t available_size, wrap_size;
int32_t base;
base = buf->get_base;
wrap_size = buf->get_head - base;
if (unlikely(wrap_size >= buf->size)) {
/* get_base is not yet adjusted */
wrap_size -= buf->size;
base += buf->size;
}
wrap_size = buf->size - wrap_size;
available_size = ring_buf_size_get(buf);
size = MIN(size, available_size);
size = MIN(size, wrap_size);
*data = &buf->buffer[buf->get_head - base];
buf->get_head += size;
return size;
}
int ring_buf_get_finish(struct ring_buf *buf, uint32_t size)
{
uint32_t finish_space, wrap_size;
finish_space = buf->get_head - buf->get_tail;
if (unlikely(size > finish_space)) {
return -1;
}
buf->get_tail += size;
buf->get_head = buf->get_tail;
wrap_size = buf->get_tail - buf->get_base;
if (unlikely(wrap_size >= buf->size)) {
/* we wrapped: adjust get_base */
buf->get_base += buf->size;
}
return 0;
}
uint32_t ring_buf_put(struct ring_buf *buf, const uint8_t *data, uint32_t size)
{
uint8_t *dst;
uint32_t partial_size;
uint32_t total_size = 0U;
// int err;
do {
partial_size = ring_buf_put_claim(buf, &dst, size);
memcpy(dst, data, partial_size);
total_size += partial_size;
size -= partial_size;
data += partial_size;
} while (size && partial_size);
ring_buf_put_finish(buf, total_size);
return total_size;
}
uint32_t ring_buf_get(struct ring_buf *buf, uint8_t *data, uint32_t size)
{
uint8_t *src;
uint32_t partial_size;
uint32_t total_size = 0U;
__unused int err;
do {
partial_size = ring_buf_get_claim(buf, &src, size);
if (data) {
memcpy(data, src, partial_size);
data += partial_size;
}
total_size += partial_size;
size -= partial_size;
} while (size && partial_size);
err = ring_buf_get_finish(buf, total_size);
return total_size;
}
int ring_buf_init(struct ring_buf *buf,
uint32_t size,
uint8_t *data)
{
if(size<=RING_BUFFER_MAX_SIZE && buf!=NULL && data!=NULL){
buf->size = size;
buf->buffer = data;
ring_buf_internal_reset(buf, 0);
return 0;
}
return -1;
}
2、ring_buffer.h
#ifndef __RING_BUFFER_H_
#define __RING_BUFFER_H_
#include <stdint.h>
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#define RING_BUFFER_MAX_SIZE 0xffff
#define likely(x) __builtin_expect((long)!!(x), 1L)
#define unlikely(x) __builtin_expect((long)!!(x), 0L)
struct ring_buf {
uint8_t *buffer;
int32_t put_head;
int32_t put_tail;
int32_t put_base;
int32_t get_head;
int32_t get_tail;
int32_t get_base;
uint32_t size;
};
uint32_t ring_buf_space_get(struct ring_buf *buf);
uint32_t ring_buf_put_claim(struct ring_buf *buf, uint8_t **data, uint32_t size);
int ring_buf_put_finish(struct ring_buf *buf, uint32_t size);
uint32_t ring_buf_get_claim(struct ring_buf *buf, uint8_t **data, uint32_t size);
int ring_buf_get_finish(struct ring_buf *buf, uint32_t size);
uint32_t ring_buf_put(struct ring_buf *buf, const uint8_t *data, uint32_t size);
uint32_t ring_buf_get(struct ring_buf *buf, uint8_t *data, uint32_t size);
int ring_buf_init(struct ring_buf *buf, uint32_t size, uint8_t *data);
#endif
3、简单使用 ring_buffer 存取
static uint8_t my_buf[100];
static struct ring_buf my_rb;
// 初始化 ring_buffer,这里使用了数组作为缓存,当然也可以使用 malloc申请的空间作为缓存
ring_buf_init(&my_rb, sizeof(my_buf), my_buf);
// 把数据放到缓存里
uint8_t data[5] = {0x01, 0x10, 0x02, 0x20, 0x66};
ring_buf_put(&my_rb, data, sizeof(data));
uint8_t data_buf[20];
uint32_t len = ring_buf_get(my_rb, data_buf, sizeof(data_buf));
4、其他 API
(1)ring_buf_space_get 用于获取ring_buffer 中未使用的缓存空间(字节)
(2)ring_buf_put_claim 和 ring_buf_put_finish 是一对的,用于存入数据到缓存中,功能与 ring_buf_put 相似,但这对函数更加高效,因为它没有拷贝;需要注意的是需要先使用 ring_buf_put_claim 再调用 ring_buf_put_finish
(3)ring_buf_get_claim 和 ring_buf_get_finish 是一对的,用于取出并使用缓存中的数据,功能与 ring_buf_get 相似,但这对函数更加高效,因为它没有拷贝;需要注意的是需要先使用 ring_buf_get_claim 再调用 ring_buf_get_finish