在嵌入式开发中,有时候数据收发速度和处理速度差别较大,若支持处理收发耗时较长,可能导致数据丢失或者增大系统响应时间。使用循环队列先把需要收发的数据存入队列,再在系统空闲是处理收发任务,可很好的解决以上的问题
循环队列原理:
参见博客 循环队列的原理
C代码实现:
ring_buf.h
/**
* File: ring_buf.h
* Date Author Notes
* 2020-11-25 dave
*/
#ifndef _RING_BUF_H_
#define _RING_BUF_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
/* ring buffer structure */
typedef struct ring_buf
{
size_t depth ; /* maximum element number */
size_t width ; /* sizeof each element */
size_t rd_idx;
size_t wr_idx;
void *buf ;
}ring_buf_t,*ring_buf_p;
bool ring_buf_init (ring_buf_p rbuf, void *buf,size_t depth, size_t width);
void ring_buf_clear(ring_buf_p rbuf);
bool ring_buf_is_full (ring_buf_p rbuf);
bool ring_buf_is_empty(ring_buf_p rbuf);
bool ring_buf_write(ring_buf_p rbuf, void *wr_data);
bool ring_buf_read (ring_buf_p rbuf, void *rd_data);
size_t ring_buf_item_count(ring_buf_p rbuf);
size_t ring_buf_left_count(ring_buf_p rbuf);
bool ring_buf_item_search(ring_buf_p rbuf,void *search_data,size_t*index);
bool ring_buf_item_copy(ring_buf_p rbuf,void *buf,size_t count);
bool ring_buf_item_remove(ring_buf_p rbuf,size_t count);
bool ring_buf_item_write(ring_buf_p rbuf, void *wr_data,size_t count);
bool ring_buf_item_read(ring_buf_p rbuf, void *rd_data,size_t count);
#ifdef __cplusplus
}
#endif
#endif
ring_buf.c
/**
* File: ring_buf.c
* Date Author Notes
* 2020-11-25 dave
*/
#include "ring_buf.h"
/**
* @brief Initialize the ring-buffer. Allocate necessary memory for the buffer.
*
* @param rbuf : Pointer to the ring-buffer object
* @param depth: Maximum element number of the buffer
* @param width: sizeof each element
*
* @return true : Succeeded
* false: Failed
*/
bool ring_buf_init(ring_buf_p rbuf, void *buf, size_t depth, size_t width)
{
if ((depth > 0) && (width > 0))
{
rbuf->depth = depth;
rbuf->width = width;
rbuf->rd_idx = 0;
rbuf->wr_idx = 0;
rbuf->buf = buf;
return rbuf->buf != NULL;
}
else
{
return false;
}
}
/**
* @brief Clear the ring-buffer object.
*
* @param rbuf: Pointer to the ring-buffer object
*/
void ring_buf_clear(ring_buf_p rbuf)
{
rbuf->rd_idx = 0;
rbuf->wr_idx = 0;
}
/**
* @brief Whether the ring-buffer is empty or not.
*
* @param rbuf: Pointer to the ring-buffer
*
* @return true : Empty. There's no elements stored in the buffer.
* false: Not empty
*/
bool ring_buf_is_empty(ring_buf_p rbuf)
{
return rbuf->rd_idx == rbuf->wr_idx;
}
/**
* @brief Whether the ring-buffer is full or not.
*
* @param rbuf: Pointer to the ring-buffer
*
* @return true : Full
* false: Not full
*/
bool ring_buf_is_full(ring_buf_p rbuf)
{
return (rbuf->rd_idx == (rbuf->wr_idx + 1)%rbuf->depth);
}
/**
* @brief Increase the buffer index while writing or reading the ring-buffer.
* @param rbuf : Pointer to the ring-buffer
* @param p_idx: Pointer to the buffer index to be increased
*/
static void ring_buf_incr(ring_buf_p rbuf, size_t *p_idx)
{
*p_idx = (*p_idx + 1) % rbuf->depth;
}
/**
* @brief Write new element to the ring-buffer.
*
* @param rbuf : Pointer to the ring-buffer object
* @param wr_data: Pointer of the new element to be written to the buffer
*
* @return true : Succeeded
* false: Failed
*/
bool ring_buf_write(ring_buf_p rbuf, void *wr_data)
{
if (ring_buf_is_full(rbuf))
{
return false;
}
else
{
memcpy(((char*)rbuf->buf + rbuf->wr_idx * rbuf->width), wr_data, rbuf->width);
ring_buf_incr(rbuf, &rbuf->wr_idx);
return true;
}
}
/**
* @brief Read from the ring-buffer
*
* @param rbuf : Pointer to the ring-buffer object
* @param rd_data: Pointer to the read result
*
* @return true : Succeeded
* false: Failed
*/
bool ring_buf_read(ring_buf_p rbuf, void *rd_data)
{
if (ring_buf_is_empty(rbuf))
{
return false;
}
else
{
memcpy(rd_data, ((char*)rbuf->buf + rbuf->rd_idx * rbuf->width), rbuf->width);
ring_buf_incr(rbuf, &rbuf->rd_idx);
return true;
}
}
/**
* @brief get the ring-buffer item count
*
* @param rbuf : Pointer to the ring-buffer object
*
* @return item count
*/
size_t ring_buf_item_count(ring_buf_p rbuf)
{
return ((rbuf->wr_idx - rbuf->rd_idx + rbuf->depth) % rbuf->depth);
}
/**
* @brief get the ring-buffer left count
*
* @param rbuf : Pointer to the ring-buffer object
*
* @return left count
*/
size_t ring_buf_left_count(ring_buf_p rbuf)
{
return (rbuf->depth - ring_buf_item_count(rbuf) - 1);
}
/**
* @brief search the ring-buffer item
*
* @param rbuf : Pointer to the ring-buffer object
*
* @return item number(0,1,2...)
*/
bool ring_buf_item_search(ring_buf_p rbuf,void *search_data,size_t*index)
{
for(size_t i = 0;i < ring_buf_item_count(rbuf);i++)
{
void *pdata = (char*)rbuf->buf + ((rbuf->rd_idx + i)%rbuf->depth) * rbuf->width;
if(memcmp(pdata,search_data,rbuf->width) == 0)
{
*index = i;
return true;
}
}
return false;
}
/**
* @brief copy the ring-buffer item
*
* @param rbuf : Pointer to the ring-buffer object
*
* @return item count
*/
bool ring_buf_item_copy(ring_buf_p rbuf,void *buf,size_t count)
{
if(count <= ring_buf_item_count(rbuf))
{
size_t cpy_idx = rbuf->rd_idx;
for(size_t i = 0;i < count;i++)
{
memcpy((char*)buf + i*rbuf->width, ((char*)rbuf->buf + cpy_idx), rbuf->width);
cpy_idx = (cpy_idx + 1)% rbuf->depth;
}
return true;
}
else
{
return false;
}
}
/**
* @brief remove the ring-buffer item
*
* @param rbuf : Pointer to the ring-buffer object
*
* @return item count
*/
bool ring_buf_item_remove(ring_buf_p rbuf,size_t count)
{
if(count <= ring_buf_item_count(rbuf))
{
rbuf->rd_idx = (rbuf->rd_idx + count)%rbuf->depth;
return true;
}
else
{
return false;
}
}
/**
* @brief Write to the ring-buffer.
*
* @param rbuf : Pointer to the ring-buffer object
* @param wr_data: Pointer of the new element to be written to the buffer
*
* @return true : Succeeded
* false: Failed
*/
bool ring_buf_item_write(ring_buf_p rbuf, void *wr_data,size_t count)
{
if(count > ring_buf_left_count(rbuf))
{
return false;
}
else
{
for(size_t i = 0;i < count;i++)
{
memcpy(((char*)rbuf->buf + rbuf->wr_idx *rbuf->width), (char*)wr_data + i *rbuf->width ,rbuf->width);
ring_buf_incr(rbuf, &rbuf->wr_idx);
}
return true;
}
}
/**
* @brief Read from the ring-buffer
*
* @param rbuf : Pointer to the ring-buffer object
* @param rd_data: Pointer to the read result
*
* @return true : Succeeded
* false: Failed
*/
bool ring_buf_item_read(ring_buf_p rbuf, void *rd_data,size_t count)
{
if(count <= ring_buf_item_count(rbuf))
{
for(size_t i = 0;i < count;i++)
{
memcpy((char*)rd_data + i*rbuf->width, ((char*)rbuf->buf + rbuf->rd_idx *rbuf->width), rbuf->width);
ring_buf_incr(rbuf, &rbuf->rd_idx);
}
return true;
}
else
{
return false;
}
}
不足之处,多多指正。