/** 
 * \file circbuff.c
 * \brief circbuff source file
 * \details File contains functions definitions for circular (ring) buffer
 *
 * \author Juraj Golej
 * \version 1.0
 */


#include "circbuff.h"

enum retCode circbuff_init(volatile struct circbuff* const This, void* const buff, const uint16_t itemSize, const uint16_t buffSize)
{
	Assert(This && buff);

	This->iActSize = 0;
	This->iReadIndex = 0;
	This->iWriteIndex = 0;

	if(!itemSize || !buffSize) {
		This->iBuff = NULL;
		return EInvalidParameter;
	}

	This->iBuff = buff;
	This->iItemSize = itemSize;
	This->iMaxSize = buffSize;

	return ENone;
}

void circbuff_deinit(volatile struct circbuff* const This)
{
	if(!This) {
		return;
	}

	This->iBuff = NULL;
	This->iItemSize = 0;
	This->iMaxSize = 0;
	This->iActSize = 0;
	This->iReadIndex = 0;
	This->iWriteIndex = 0;
}

enum retCode circbuff_push(volatile struct circbuff* const This, const void* const data)
{
	if(!This || !data || !This->iBuff) {
		return ENullPtr;
	}

	if(This->iActSize == This->iMaxSize) {
		return EOverflow;
	}

	const uint8_t* const tmpData = (const uint8_t*)data;
	uint8_t* const tmpBuff = (uint8_t*)This->iBuff + This->iWriteIndex * This->iItemSize;
	
	for(uint16_t i = 0; i < This->iItemSize; ++i) {
		tmpBuff[i] = tmpData[i];
	}

	++This->iActSize;

	if(This->iWriteIndex == This->iMaxSize - 1) {
		This->iWriteIndex = 0;
	}
	else {
		++This->iWriteIndex;
	}

	return ENone;
}

enum retCode circbuff_pull(volatile struct circbuff* const This, void* const data)
{
	if(!This || !data) {
		return ENullPtr;
	}

	if(This->iActSize == 0) {
		return EDenied;
	}

	uint8_t* const tmpData = (uint8_t*)data;
	const uint8_t* const tmpBuff = (uint8_t*)This->iBuff + This->iReadIndex * This->iItemSize;

	for(uint16_t i = 0; i < This->iItemSize; ++i) {
		tmpData[i] = tmpBuff[i];
	}

	--This->iActSize;

	if(This->iReadIndex == This->iMaxSize - 1) {
		This->iReadIndex = 0;
	}
	else {
		++This->iReadIndex;
	}

	return ENone;
}