/****************************************************************************** 版权所有 (C), 2018-2099, Radkil_Std ****************************************************************************** 文 件 名 : ringbuffer.c 版 本 号 : 初稿 作 者 : Radkil 生成日期 : 2023年3月26日 最近修改 : 功能描述 : ringbuffer环形缓冲区实现 修改历史 : 1.日 期 : 2023年3月26日 作 者 : Radkil 修改内容 : 创建文件 ******************************************************************************/ #include #include #include #include "ringbuffer.h" #include "common.h" /*----------------------------------------------* * 外部变量说明 * *----------------------------------------------*/ /*----------------------------------------------* * 外部函数原型说明 * *----------------------------------------------*/ /*----------------------------------------------* * 内部函数原型说明 * *----------------------------------------------*/ /*----------------------------------------------* * 全局变量 * *----------------------------------------------*/ /*----------------------------------------------* * 模块级变量 * *----------------------------------------------*/ /*----------------------------------------------* * 常量定义 * *----------------------------------------------*/ /*----------------------------------------------* * 宏定义 * *----------------------------------------------*/ /** * @brief Initialize the ring buffer object. * * @param rb A pointer to the ring buffer object. * @param pool A pointer to the buffer. * @param size The size of the buffer in bytes. */ void rd_RingbufferInit(rd_ringbuf_t *rb, char *pool, int size) { if(NULL == rb || NULL == pool || size <= 0) { return; } /* initialize read and write index */ rb->m_bReadMirror = rb->m_sReadIndex = 0; rb->m_bWriteMirror = rb->m_sWriteIndex = 0; /* set buffer pool and size */ rb->m_pcBufPtr = pool; rb->m_iBufsize = RD_ALIGN_DOWN(size, RD_ALIGN_SIZE); } /** * @brief Put a block of data into the ring buffer. If the capacity of ring buffer is insufficient, it will discard out-of-range data. * * @param rb A pointer to the ring buffer object. * @param ptr A pointer to the data buffer. * @param length The size of data in bytes. * * @return Return the data size we put into the ring buffer. */ int rd_RingbufferPut(rd_ringbuf_t *rb, const char *ptr, int length) { int size = 0; if(NULL == rb || NULL == ptr || length <= 0) { return RD_INVALUE; } /* whether has enough space */ size = rd_RingbufferSpaceLen(rb); /* no space */ if (size == 0) { return 0; } /* drop some data */ if (size < length) { length = size; } if (rb->m_iBufsize - rb->m_sWriteIndex > length) { /* m_sReadIndex - m_sWriteIndex = empty space */ RD_MEMCPY(&rb->m_pcBufPtr[rb->m_sWriteIndex], ptr, length); /* this should not cause overflow because there is enough space for * length of data in current mirror */ rb->m_sWriteIndex += length; return length; } RD_MEMCPY(&rb->m_pcBufPtr[rb->m_sWriteIndex], &ptr[0], rb->m_iBufsize - rb->m_sWriteIndex); RD_MEMCPY(&rb->m_pcBufPtr[0], &ptr[rb->m_iBufsize - rb->m_sWriteIndex], length - (rb->m_iBufsize - rb->m_sWriteIndex)); /* we are going into the other side of the mirror */ rb->m_bWriteMirror = ~rb->m_bWriteMirror; rb->m_sWriteIndex = length - (rb->m_iBufsize - rb->m_sWriteIndex); return length; } /** * @brief Put a block of data into the ring buffer. If the capacity of ring buffer is insufficient, it will overwrite the existing data in the ring buffer. * * @param rb A pointer to the ring buffer object. * @param ptr A pointer to the data buffer. * @param length The size of data in bytes. * * @return Return the data size we put into the ring buffer. */ int rd_RingbufferPutForce(rd_ringbuf_t *rb, const char *ptr, int length) { int space_length; if (NULL == rb || NULL == ptr || length <= 0) { return RD_INVALUE; } space_length = rd_RingbufferSpaceLen(rb); if (length > rb->m_iBufsize) { ptr = &ptr[length - rb->m_iBufsize]; length = rb->m_iBufsize; } if (rb->m_iBufsize - rb->m_sWriteIndex > length) { /* m_sReadIndex - m_sWriteIndex = empty space */ RD_MEMCPY(&rb->m_pcBufPtr[rb->m_sWriteIndex], ptr, length); /* this should not cause overflow because there is enough space for * length of data in current mirror */ rb->m_sWriteIndex += length; if (length > space_length) rb->m_sReadIndex = rb->m_sWriteIndex; return length; } RD_MEMCPY(&rb->m_pcBufPtr[rb->m_sWriteIndex], &ptr[0], rb->m_iBufsize - rb->m_sWriteIndex); RD_MEMCPY(&rb->m_pcBufPtr[0], &ptr[rb->m_iBufsize - rb->m_sWriteIndex], length - (rb->m_iBufsize - rb->m_sWriteIndex)); /* we are going into the other side of the mirror */ rb->m_bWriteMirror = ~rb->m_bWriteMirror; rb->m_sWriteIndex = length - (rb->m_iBufsize - rb->m_sWriteIndex); if (length > space_length) { if (rb->m_sWriteIndex <= rb->m_sReadIndex) rb->m_bReadMirror = ~rb->m_bReadMirror; rb->m_sReadIndex = rb->m_sWriteIndex; } return length; } /** * @brief Get data from the ring buffer. * * @param rb A pointer to the ring buffer. * @param ptr A pointer to the data buffer. * @param length The size of the data we want to read from the ring buffer. * * @return Return the data size we read from the ring buffer. */ int rd_RingbufferGet(rd_ringbuf_t *rb, char *ptr, int length) { int size; if (NULL == rb || NULL == ptr || length <= 0) { return RD_INVALUE; } /* whether has enough data */ size = rd_RingbufferDataLen(rb); /* no data */ if (size == 0) { return 0; } /* less data */ if (size < length) { length = size; } if (rb->m_iBufsize - rb->m_sReadIndex > length) { /* copy all of data */ RD_MEMCPY(ptr, &rb->m_pcBufPtr[rb->m_sReadIndex], length); /* this should not cause overflow because there is enough space for * length of data in current mirror */ rb->m_sReadIndex += length; return length; } RD_MEMCPY(&ptr[0], &rb->m_pcBufPtr[rb->m_sReadIndex], rb->m_iBufsize - rb->m_sReadIndex); RD_MEMCPY(&ptr[rb->m_iBufsize - rb->m_sReadIndex], &rb->m_pcBufPtr[0], length - (rb->m_iBufsize - rb->m_sReadIndex)); /* we are going into the other side of the mirror */ rb->m_bReadMirror = ~rb->m_bReadMirror; rb->m_sReadIndex = length - (rb->m_iBufsize - rb->m_sReadIndex); return length; } /** * @brief Get the first readable byte of the ring buffer. * * @param rb A pointer to the ringbuffer. * @param ptr When this function return, *ptr is a pointer to the first readable byte of the ring buffer. * * @note It is recommended to read only one byte, otherwise it may cause buffer overflow. * * @return Return the size of the ring buffer. */ int rd_RingbufferPeak(rd_ringbuf_t *rb, char **ptr) { int size; if (NULL == rb) { return RD_INVALUE; } *ptr = NULL; /* whether has enough data */ size = rd_RingbufferDataLen(rb); /* no data */ if (size == 0) { return 0; } *ptr = &rb->m_pcBufPtr[rb->m_sReadIndex]; if((int)(rb->m_iBufsize - rb->m_sReadIndex) > size) { return size; } size = rb->m_iBufsize - rb->m_sReadIndex; /* we are going into the other side of the mirror */ //rb->m_bReadMirror = ~rb->m_bReadMirror; //rb->m_sReadIndex = 0; return size; } /** * @brief Put a byte into the ring buffer. If ring buffer is full, this operation will fail. * * @param rb A pointer to the ring buffer object. * @param ch A byte put into the ring buffer. * * @return Return the data size we put into the ring buffer. The ring buffer is full if returns 0. Otherwise, it will return 1. */ int rd_RingbufferPutchar(rd_ringbuf_t *rb, const char ch) { if (NULL == rb) { return RD_INVALUE; } /* whether has enough space */ if (!rd_RingbufferSpaceLen(rb)) { return 0; } rb->m_pcBufPtr[rb->m_sWriteIndex] = ch; /* flip mirror */ if (rb->m_sWriteIndex == rb->m_iBufsize-1) { rb->m_bWriteMirror = ~rb->m_bWriteMirror; rb->m_sWriteIndex = 0; } else { rb->m_sWriteIndex++; } return 1; } /** * @brief Put a byte into the ring buffer. If ring buffer is full, it will discard an old data and put into a new data. * * @param rb A pointer to the ring buffer object. * @param ch A byte put into the ring buffer. * * @return Return the data size we put into the ring buffer. Always return 1. */ int rd_RingbufferPutcharForce(rd_ringbuf_t *rb, const char ch) { enum ERingBufState old_state; if (NULL == rb) { return RD_INVALUE; } old_state = rd_RingbufferStatus(rb); rb->m_pcBufPtr[rb->m_sWriteIndex] = ch; /* flip mirror */ if (rb->m_sWriteIndex == rb->m_iBufsize-1) { rb->m_bWriteMirror = ~rb->m_bWriteMirror; rb->m_sWriteIndex = 0; if (old_state == RINGBUFFER_FULL) { rb->m_bReadMirror = ~rb->m_bReadMirror; rb->m_sReadIndex = rb->m_sWriteIndex; } } else { rb->m_sWriteIndex++; if (old_state == RINGBUFFER_FULL) { rb->m_sReadIndex = rb->m_sWriteIndex; } } return 1; } /** * @brief Get a byte from the ring buffer. * * @param rb The pointer to the ring buffer object. * @param ch A pointer to the buffer, used to store one byte. * * @return 0 The ring buffer is empty. * @return 1 Success */ int rd_RingbufferGetchar(rd_ringbuf_t *rb, char *ch) { if (NULL == rb) { return RD_INVALUE; } /* ringbuffer is empty */ if (!rd_RingbufferDataLen(rb)) { return 0; } /* put byte */ *ch = rb->m_pcBufPtr[rb->m_sReadIndex]; if (rb->m_sReadIndex == rb->m_iBufsize-1) { rb->m_bReadMirror = ~rb->m_bReadMirror; rb->m_sReadIndex = 0; } else { rb->m_sReadIndex++; } return 1; } /** * @brief Get the size of data in the ring buffer in bytes. * * @param rb The pointer to the ring buffer object. * * @return Return the size of data in the ring buffer in bytes. */ int rd_RingbufferDataLen(rd_ringbuf_t *rb) { switch (rd_RingbufferStatus(rb)) { case RINGBUFFER_EMPTY: return 0; case RINGBUFFER_FULL: return rb->m_iBufsize; case RINGBUFFER_HALFFULL: default: { int wi = rb->m_sWriteIndex, ri = rb->m_sReadIndex; if (wi > ri) { return wi - ri; } else { return rb->m_iBufsize - (ri - wi); } } } } /** * @brief Reset the ring buffer object, and clear all contents in the buffer. * * @param rb A pointer to the ring buffer object. */ void rd_RingbufferReset(rd_ringbuf_t *rb) { if(NULL == rb) { return; } rb->m_bReadMirror = 0; rb->m_sReadIndex = 0; rb->m_bWriteMirror = 0; rb->m_sWriteIndex = 0; } /** * @brief Create a ring buffer object with a given size. * * @param size The size of the buffer in bytes. * * @return Return a pointer to ring buffer object. When the return value is RT_NULL, it means this creation failed. */ rd_ringbuf_t *rd_RingbufferCreate(int size) { rd_ringbuf_t *rb; char *pool; if (size <= 0) { return NULL; } size = RD_ALIGN_DOWN(size, RD_ALIGN_SIZE); rb = (rd_ringbuf_t *)RD_MALLOC(sizeof(rd_ringbuf_t)); if (rb == NULL) { goto exit; } pool = (char *)RD_MALLOC(size); if (pool == NULL) { RD_FREE(rb); rb = NULL; goto exit; } rd_RingbufferInit(rb, pool, size); exit: return rb; } /** * @brief Destroy the ring buffer object, which is created by rt_ringbuffer_create() . * * @param rb A pointer to the ring buffer object. */ void rd_RingbufferDestroy(rd_ringbuf_t *rb) { if (NULL == rb) { return; } RD_FREE(rb->m_pcBufPtr); RD_FREE(rb); }