Files
CuboBmsFirmware/firmware/Libs/RingBuffer/RingBuffer.c
Dmitriy Semenov 9c2667bbe5 CAN Update
2023-04-03 21:51:33 +03:00

237 lines
6.8 KiB
C

/**
*******************************************
* @file RingBuffer.c
* @author Dmitriy Semenov / Crazy_Geeks
* @version 1.2
* @date 05-March-2022
* @brief Source file for RingBuffer lib
* @note https://crazygeeks.ru/c-ringbuffer/
*******************************************
*/
#include "RingBuffer.h"
/**
* @addtogroup RING_BUF
* @{
*/
/**
* @brief Init ring buffer
*
* @param[in] buf Pointer to the allocated buffer
* @param[in] size Size of buffer
* @param[in] cellsize Size of 1 cell [bytes]
* @param[in] rb #RINGBUF_t structure instance
* @return #RINGBUF_STATUS enum
*/
RINGBUF_STATUS RingBuf_Init(void *buf, u16_t size, size_t cellsize, RINGBUF_t *rb) {
rb->size = size; // size of array
rb->cell_size = cellsize; // size of 1 cell of array
rb->buf = buf; // set pointer to buffer
RingBuf_Clear(rb); // clear all
return rb->buf ? RINGBUF_OK : RINGBUF_PARAM_ERR;
}
/**
* @brief Clear ring buffer
* @note Disable interrupts while clearing
*
* @param[in] rb #RINGBUF_t structure instance
* @return #RINGBUF_STATUS enum
*/
RINGBUF_STATUS RingBuf_Clear(RINGBUF_t *rb) {
if (rb->buf == NULL) return RINGBUF_PARAM_ERR;
rb->head = rb->tail = 0;
return RINGBUF_OK;
}
/**
* @brief Check available size to read
*
* @param[out] len Size to read [bytes]
* @param[in] rb #RINGBUF_t structure instance
* @return #RINGBUF_STATUS enum
*/
RINGBUF_STATUS RingBuf_Available(u16_t *len, RINGBUF_t *rb) {
if (rb->buf == NULL) return RINGBUF_PARAM_ERR;
if (rb->head < rb->tail)
*len = rb->size - rb->tail + rb->head;
else
*len = rb->head - rb->tail;
return RINGBUF_OK;
}
/**
* @brief Put byte to the buffer
*
* @param[in] data Data byte to be put [bytes]
* @param[in] rb #RINGBUF_t structure instance
* @return #RINGBUF_STATUS enum
*/
RINGBUF_STATUS RingBuf_BytePut(const u8_t data, RINGBUF_t *rb) {
if (rb->buf == NULL) return RINGBUF_PARAM_ERR;
rb->buf[rb->head++] = data; // put byte in cell and increment data
if (rb->head >= rb->size) // if overflow
rb->head = 0; // set to start
return RINGBUF_OK;
}
/**
* @brief Put 1 cell to the buffer
* @param[in] data Pointer to data
* @param[in] rb #RINGBUF_t structure instance
* @return #RINGBUF_STATUS enum
*/
RINGBUF_STATUS RingBuf_CellPut(const void *data, RINGBUF_t *rb) {
return RingBuf_DataPut(data, 1, rb);
}
/**
* @brief Put some data to the buffer
*
* @param[in] data Data to be put
* @param[in] len Length of data to be written [bytes]
* @param[in] rb #RINGBUF_t structure instance
* @return #RINGBUF_STATUS enum
*/
RINGBUF_STATUS RingBuf_DataPut(const void *data, u16_t len, RINGBUF_t *rb) {
if (rb->buf == NULL) return RINGBUF_PARAM_ERR;
if (len > rb->size)
return RINGBUF_OVERFLOW;
const char *input = data; // recast pointer
// INPUT data index start address
size_t s_addr = 0;
// available space in the end of buffer
size_t space = rb->size - rb->head;
if (len > space) { // if len > available space
// copy data to available space
memcpy(&rb->buf[rb->head*rb->cell_size], &input[s_addr * rb->cell_size], space * rb->cell_size);
// next writing will start from 0
rb->head = 0;
// new start address = space length
s_addr = space;
// new length = len-space
len -= space;
}
// copy all the data to the buf storage
memcpy(&rb->buf[rb->head*rb->cell_size], &input[s_addr * rb->cell_size], len * rb->cell_size);
// shift to the next head
rb->head += len;
if (rb->head >= rb->size)
rb->head = 0;
return RINGBUF_OK;
}
/**
* @brief Read next byte from the buffer
*
* @param[out] data Data byte from the buffer
* @param[in] rb #RINGBUF_t structure instance
* @return #RINGBUF_STATUS enum
*/
RINGBUF_STATUS RingBuf_ByteRead(u8_t *data, RINGBUF_t *rb) {
if (rb->buf == NULL) return RINGBUF_PARAM_ERR;
RINGBUF_STATUS st = RingBuf_ByteWatch(data, rb);
if (st != RINGBUF_OK)
return st;
rb->tail++;
if (rb->tail >= rb->size)
rb->tail = 0;
return st;
}
/**
* @brief Read 1 cell from buf
* @param[out] data Data cell from the buffer
* @param[in] rb #RINGBUF_t structure instance
* @return #RINGBUF_STATUS enum
*/
RINGBUF_STATUS RingBuf_CellRead(void *data, RINGBUF_t *rb) {
return RingBuf_DataRead(data, 1, rb);
}
/**
* @brief Read some next data from the buffer
*
* @param[out] data Data from the buffer
* @param[in] len Length of data to be read [bytes]
* @param[in] rb #RINGBUF_t structure instance
* @return #RINGBUF_STATUS enum
*/
RINGBUF_STATUS RingBuf_DataRead(void *data, u16_t len, RINGBUF_t *rb) {
if (rb->buf == NULL) return RINGBUF_PARAM_ERR;
// read data
RINGBUF_STATUS st = RingBuf_DataWatch(data, len, rb);
if (st != RINGBUF_OK)
return st;
// shift to the next head
rb->tail += len;
if (rb->tail >= rb->size)
rb->tail = 0;
return st;
}
/**
* @brief Watch current byte in buf
* @note Reads data without shifting in the buffer
*
* @param[out] data Pointer to data byte got from buffer
* @param[in] rb #RINGBUF_t structure instance
* @return #RINGBUF_STATUS enum
*/
RINGBUF_STATUS RingBuf_ByteWatch(u8_t *data, RINGBUF_t *rb) {
if (data == NULL) return RINGBUF_PARAM_ERR;
*data = rb->buf[rb->tail];
return RINGBUF_OK;
}
/**
* @brief Watch 1 cell from buf
* @note Reads data without shifting in the buffer
*
* @param[out] data Pointer to data cell got from buffer
* @param[in] #RINGBUF_t structure instance
* @return #RINGBUF_STATUS enum
*/
RINGBUF_STATUS RingBuf_CellWatch(void *data, RINGBUF_t *rb) {
return RingBuf_DataWatch(data, 1, rb);
}
/**
* @brief Watch current data in the buf
* @note Reads data without shifting in the buffer
*
* @param[out] data Data from buffer
* @param[in] len Length of data to be read [bytes]
* @param[in] rb #RINGBUF_t structure instance
* @return #RINGBUF_STATUS enum
*/
RINGBUF_STATUS RingBuf_DataWatch(void *data, u16_t len, RINGBUF_t *rb) {
if (data == NULL)
return RINGBUF_PARAM_ERR;
if (len > rb->size)
return RINGBUF_OVERFLOW;
// OUTPUT data index start address
u16_t s_addr = 0;
// available space in the end of buffer
u16_t space = rb->size - rb->tail;
u16_t loc_tail = rb->tail;
if (len > space) { // if len > available space
// recast pointer to u8_t
// copy data from available space
memcpy(&data[s_addr * rb->cell_size], &rb->buf[loc_tail * rb->cell_size], space * rb->cell_size);
// next reading will start from 0
loc_tail = 0;
// new start address - space length
s_addr = space;
// new length - len-space
len -= space;
}
// copy all the data from the buf storage
memcpy(&data[s_addr * rb->cell_size], &rb->buf[loc_tail * rb->cell_size], len * rb->cell_size);
return RINGBUF_OK;
}
/// @} RING_BUF Group