ringbuffer.c 3.82 KB
#include "ringbuffer.h"
#include "string.h"

#ifdef FREERTOS
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "timers.h"
#include "semphr.h"
#include "portmacro.h"

xSemaphoreHandle xSemaphore_RINGBUF = NULL;
#endif

#define WRITE_SUCCEED 0
#define READ_SUCCESS 0

#define FAIL_LACK_OF_SPACE -1
#define FAIL_READ_TOO_FAST -2

static uint16_t WRITE_ID;
static uint16_t READ_ID;
static uint16_t BUF_LEN;
static uint8_t *RING_BUFFER;

uint16_t RingBuffer_everMAX = 0;

/***************************RINGBUF_SEND***************************/
/*
*warning:this API is not safe for interrupt operation,please ensure only one IRQ functions call this function.
*/
int8_t RINGBUF_SEND(const char *buffer,uint16_t len)
{
	if(len > RINGBUF_AVALIABLE_SPACE())
	{
		return FAIL_LACK_OF_SPACE;
	}

	uint16_t distance = BUF_LEN - WRITE_ID;
	if(distance>len)
	{
		memcpy((void *)&RING_BUFFER[WRITE_ID],buffer,len);
		WRITE_ID += len;
	}
	else
	{
		memcpy((void *)&RING_BUFFER[WRITE_ID],buffer,distance);
		WRITE_ID = 0;
		if(len-distance)
		{
			memcpy((void *)&RING_BUFFER[WRITE_ID],buffer+distance,len-distance);
			WRITE_ID = len-distance;
		}
	}

	(WRITE_ID+BUF_LEN-READ_ID)%BUF_LEN > RingBuffer_everMAX ? RingBuffer_everMAX = (WRITE_ID+BUF_LEN-READ_ID)%BUF_LEN : 1;

	return WRITE_SUCCEED;
}

/***************************RINGBUF_READ***************************/
int8_t RINGBUF_READ(uint8_t *buffer,uint16_t len)
{
#ifdef FREERTOS 
	xSemaphoreTake( xSemaphore_RINGBUF, portMAX_DELAY );//take Mutex for read
#endif

	if(len > (BUF_LEN - RINGBUF_AVALIABLE_SPACE()))
	{
#ifdef FREERTOS 
		xSemaphoreGive( xSemaphore_RINGBUF );
#endif

		return FAIL_READ_TOO_FAST;
	}
	uint16_t distance = BUF_LEN - READ_ID;
	if(distance>len)
	{
		memcpy((void *)buffer,&RING_BUFFER[READ_ID],len);
		READ_ID += len;
	}
	else
	{
		memcpy((void *)buffer,&RING_BUFFER[READ_ID],distance);
		READ_ID = 0;
		if(len-distance)
		{
			memcpy((void *)(buffer+distance),&RING_BUFFER[READ_ID],len-distance);
			READ_ID = len-distance;
		}
	}
	*(buffer+len) = NULL;

#ifdef FREERTOS 
	xSemaphoreGive( xSemaphore_RINGBUF );//give Mutex for read
#endif

	return READ_SUCCESS;
}

/***************************RINGBUF_PEEK***************************/
int8_t RINGBUF_PEEK(uint8_t *buffer,uint16_t len)
{	
#ifdef FREERTOS 
	xSemaphoreTake( xSemaphore_RINGBUF, portMAX_DELAY );//take Mutex for read
#endif

	if(len > (BUF_LEN - RINGBUF_AVALIABLE_SPACE()))
	{
#ifdef FREERTOS 
		xSemaphoreGive( xSemaphore_RINGBUF );
#endif

		return FAIL_READ_TOO_FAST;
	}
	uint16_t readpoint = READ_ID;
	uint16_t distance = BUF_LEN - readpoint;
	if(distance>len)
	{
		memcpy((void *)buffer,&RING_BUFFER[readpoint],len);
		readpoint += len;
	}
	else
	{
		memcpy((void *)buffer,&RING_BUFFER[readpoint],distance);
		readpoint = 0;
		if(len-distance)
		{
			memcpy((void *)(buffer+distance),&RING_BUFFER[readpoint],len-distance);
			readpoint = len-distance;
		}
	}
	*(buffer+len) = NULL;
	
#ifdef FREERTOS 
	xSemaphoreGive( xSemaphore_RINGBUF );
#endif

	return READ_SUCCESS;
}

/***************************RINGBUF_INIT***************************/
void RINGBUF_INIT(uint8_t * ringbuffer,uint16_t len)
{
#ifdef FREERTOS
	xSemaphore_RINGBUF = xSemaphoreCreateMutex();
#endif
	
	WRITE_ID = 0;
	READ_ID = 0;
	RING_BUFFER = ringbuffer;
	BUF_LEN = len;
	memset(RING_BUFFER,0x00,BUF_LEN);
}

/***************************RINGBUF_CHECKIO************************/
uint8_t RINGBUF_CHECKIO(void)
{
	if(READ_ID == WRITE_ID)
		return 0;
	else
		return 1;
}

/****************************RINGBUF_AVALIABLE_SPACE***************/
uint16_t RINGBUF_AVALIABLE_SPACE()
{
	uint16_t len = 0;
	if(WRITE_ID < READ_ID)
	{
		len = READ_ID - WRITE_ID;
	}
	else
	{
		len = BUF_LEN - (WRITE_ID - READ_ID);
	}
	return len;
}