/**
@file ecarx_ringbuffer.c
@brief Ring Buffer.
*/

/********************************************************************************************
Debug Switch Definition Section
********************************************************************************************/

/********************************************************************************************
Include File Section
********************************************************************************************/
#include "stddef.h"
#include "ecarx_ringbuffer.h"
#include "stdarg.h"
#include "string.h"
/********************************************************************************************
Macro Definition Section
********************************************************************************************/
#define RB_SEM_WAIT_TIME		(10)
#define wvdGen_MemCpy			memcpy
#define STATUS_SUCCESS		1
#define Ecrax_SemaWait(sem ,tm)		STATUS_SUCCESS;	//SuspendOSInterrupts()
#define Ecrax_SemaPost(sem)				STATUS_SUCCESS; //ResumeOSInterrupts()
/********************************************************************************************
Prototype Declaration Section
********************************************************************************************/
RB_STATUS xRBInit(RB *rb, uint8_t *pdata, uint32_t nMaxsize, uint16_t sem);
RB_STATUS xRBPushStatusCheck(RB *rb, uint8_t *pdata, uint8_t nSize);
RB_STATUS xRBPush(RB *rb,  uint8_t *pdata, uint8_t nSize);
RB_STATUS xRBPopCopy(RB *rb, uint8_t *pdata, uint8_t nMaxSize,uint8_t *pucnCurBlkSize);
RB_STATUS xRBPop(RB *rb, uint8_t *pdata, uint8_t nMaxSize);
RB_STATUS xRBPopMultiple(RB *rb, uint8_t *pdata, uint32_t nMaxSize);
RB_STATUS xRBPushCpyCheck(RB *rb_cpy,RB *rb,RB_STATUS Status);
RB_STATUS xRBPopCpyCheck(RB *rb_cpy,RB *rb);
/********************************************************************************************
Const Global Variable Definition Section
********************************************************************************************/

/********************************************************************************************
Global Variable Definition Section
********************************************************************************************/

/********************************************************************************************
Static Variable Definition Section
********************************************************************************************/

/********************************************************************************************
Structure Type Definition Section
********************************************************************************************/

/********************************************************************************************
Function Definition Section
********************************************************************************************/
/**
 * xRBInit
 * Author qiuxf
 * @param rb pointer to ring buffer
 * @param pdata pointer to data
 * @param maxsize ringbuffer size
 * @param sem semaphort id of ring buffer
 * @return status
 */
RB_STATUS xRBInit(RB *rb, uint8_t *pdata, uint32_t nMaxsize, uint16_t sem)
{
	//uint8_t status;
	RB_STATUS ret = RB_OK;
	rb->m_sem = sem;

	if(pdata == SAF_NULL)
	{
		ret = RB_ILLEGAL_DATA_PTR;
	}
	else
	{
		rb->m_pdata = pdata;
		rb->m_phead = pdata;
		rb->m_ptail = pdata;
		rb->m_max_size = nMaxsize;
		rb->m_free_size = nMaxsize;
		rb->m_len = 0;
		rb->m_error = 0;
	}
	rb->m_initFlag = RB_INITED;
	return ret;
}

RB_STATUS xRBPushStatusCheck(RB *rb, uint8_t *pdata, uint8_t nSize)
{
	RB_STATUS aubRet = RB_OK;
	if(rb != SAF_NULL)
	{
		if(RB_INITED != rb->m_initFlag)
		{
		
			aubRet = RB_UNINITED;
		}

		if(rb->m_free_size < (uint32_t)(nSize + 1))
		{
			
			aubRet = RB_FULL;		/*no enough area*/
		}
		if(SAF_NULL != pdata)
		{
		
			aubRet = RB_ILLEGAL_DATA_PTR;
		}
	}
	else
	{
		
		aubRet = RB_ILLEGAL_DATA_PTR;
	}
	return aubRet;
}

/**
 * xRBPush
 * Author qiuxf
 * @param rb pointer to ring buffer
 * @param pdata pointer to data
 * @ param nSize size
 * @return status
 */
RB_STATUS xRBPush(RB *rb,  uint8_t *pdata, uint8_t nSize)
{
	int32_t nCurToEnd = 0;
	RB_STATUS aubRet = RB_OK;

	if(RB_INITED != rb->m_initFlag)
	{
		aubRet = RB_UNINITED;
	}
	if(rb->m_free_size < (uint32_t)(nSize + 1))
	{
		aubRet = RB_FULL;		/*no enough area*/
	}

	if(RB_OK == aubRet)
	{
		*rb->m_ptail = nSize;			/*copy length*/
		rb->m_ptail++;

		nCurToEnd = ((rb->m_pdata + rb->m_max_size) - rb->m_ptail);
		if(nCurToEnd >= nSize)
		{
			if(SAF_NULL != pdata)
			{
				wvdGen_MemCpy( rb->m_ptail , pdata, nSize);
			}
			rb->m_ptail += nSize;
		}
		else
		{
			if(SAF_NULL != pdata)
			{				
				wvdGen_MemCpy(rb->m_ptail, pdata, nCurToEnd); //copy from tail to end
				wvdGen_MemCpy(rb->m_pdata, pdata + nCurToEnd, nSize - nCurToEnd); //copy from head
			}
			rb->m_ptail = ((rb->m_pdata + nSize) - nCurToEnd);
		}

		if(rb->m_ptail == (rb->m_pdata + rb->m_max_size))
		{
			rb->m_ptail = rb->m_pdata;
		}
		else
		{
			;
		}
		rb->m_free_size -= (nSize + 1);
		rb->m_len++;
	}
	return aubRet;
}
/**
 * xRBPush
 * Author qiuxf
 * @param rb pointer to ring buffer
 * @param pdata pointer to data
 * @ param nMaxSize size
 * @return status
 */
RB_STATUS xRBPopCopy(RB *rb, uint8_t *pdata, uint8_t nMaxSize,uint8_t *pucnCurBlkSize)
{
	int32_t nCurToEnd = 0;
	uint8_t nCurBlkSize = 0;
	uint8_t aubRet = RB_OK;
	(void)nMaxSize;
	if((rb == SAF_NULL) || (pucnCurBlkSize == SAF_NULL))
	{
		aubRet = RB_ILLEGAL_DATA_PTR;
	}
	else
	{
		rb->m_phead++;
		nCurBlkSize = *pucnCurBlkSize;
		nCurToEnd = ((rb->m_pdata + rb->m_max_size) - rb->m_phead);
		if(nCurToEnd >= nCurBlkSize)
		{
			if(SAF_NULL != pdata)
			{
				wvdGen_MemCpy(pdata, rb->m_phead, nCurBlkSize);
			}
			else
			{
				aubRet = RB_ILLEGAL_DATA_PTR;
			}
			rb->m_phead += nCurBlkSize;
		}
		else
		{
			if(SAF_NULL != pdata)
			{				
				wvdGen_MemCpy(pdata, rb->m_phead, nCurToEnd); //copy current pointer to end of data buffer				
				wvdGen_MemCpy(pdata + nCurToEnd, rb->m_pdata, nCurBlkSize - nCurToEnd); //copy lest data
			}
			else
			{
				aubRet = RB_ILLEGAL_DATA_PTR;
			}
			rb->m_phead = ((rb->m_pdata + nCurBlkSize) - nCurToEnd);
		}
		if(rb->m_phead == (rb->m_pdata + rb->m_max_size))
		{
			rb->m_phead = rb->m_pdata;
		}
		rb->m_free_size += (nCurBlkSize + 1);
		rb->m_len--;
	}
	return aubRet;
}

RB_STATUS xRBPop(RB *rb, uint8_t *pdata, uint8_t nMaxSize)
{
//	int32_t nCurToEnd = 0;
	uint8_t nCurBlkSize = 0;
	RB_STATUS aubRet = RB_OK;

	if(SAF_NULL == rb)
	{
		aubRet = RB_ILLEGAL_DATA_PTR;
	}
	else
	{
		if(RB_INITED != rb->m_initFlag)
		{
			aubRet = RB_UNINITED;
		}
		if(0 == rb->m_len)
		{
			aubRet = RB_EMPTY;
		}
	}

	if(RB_OK == aubRet)
	{
		nCurBlkSize = *rb->m_phead;
		if(SAF_NULL != pdata)
		{
			if(nCurBlkSize > nMaxSize)
			{
				aubRet = RB_ILLEGAL_ELE_SIZE;
			}
		}
		if(RB_OK == aubRet)
		{
			aubRet = xRBPopCopy(rb,pdata,nMaxSize,&nCurBlkSize);
		}
	}
	return aubRet;
}

RB_STATUS xRBPopMultiple(RB *rb, uint8_t *pdata, uint32_t nMaxSize)
{
	//int32_t nCurToEnd = 0;
	uint8_t nCurBlkSize = 0;
	uint16_t nCurTotalSize = 0;
	RB_STATUS aubRet = RB_OK;

	if(SAF_NULL == rb)
	{
		aubRet = RB_ILLEGAL_DATA_PTR;;
	}
	else
	{
		if(RB_INITED != rb->m_initFlag)
		{
			aubRet = RB_UNINITED;
		}
		if(0 == rb->m_len)
		{
			aubRet = RB_EMPTY;
		}
	}

	if(RB_OK == aubRet)
	{
		nCurBlkSize = *rb->m_phead;
		nCurTotalSize = nCurBlkSize;
		if(nCurBlkSize > nMaxSize)
		{
			aubRet = RB_ILLEGAL_ELE_SIZE;
		}
		while((nCurTotalSize < nMaxSize) && (rb->m_len > 0))
		{
			if(RB_OK == aubRet)
			{
				aubRet = xRBPopCopy(rb,pdata,nMaxSize,&nCurBlkSize);
				if(rb->m_len > 0)
				{
					pdata = pdata + nCurBlkSize;
					nCurBlkSize = *rb->m_phead;
					nCurTotalSize += nCurBlkSize;				
				}
			}
		}
	}
	return aubRet;
}

RB_STATUS xRBPushCpyCheck(RB *rb_cpy,RB *rb,RB_STATUS Status)
{
	RB_STATUS aubRet = RB_OK;
	
	if((SAF_NULL == rb) || (SAF_NULL == rb_cpy))
	{
		aubRet = RB_ILLEGAL_DATA_PTR;
	}
	else
	{
		if((RB_INITED != rb->m_initFlag) || (RB_INITED != rb_cpy->m_initFlag))
		{
			aubRet = RB_UNINITED;
		}
	}
	
	if(RB_OK == aubRet)
	{
		if(Status == RB_FULL)	
		{
			rb_cpy->m_ptail = rb->m_ptail;
			rb_cpy->m_free_size = rb->m_free_size;
			rb_cpy->m_len = rb->m_len;
			rb_cpy->m_error = 1;
			//rb_cpy->m_phead = rb->m_phead;
		}
		else
		{
			rb_cpy->m_error = 0; 
		}
	}
	return aubRet;
}

RB_STATUS xRBPopCpyCheck(RB *rb_cpy,RB *rb)
{
	RB_STATUS aubRet = RB_OK;
			
	if((SAF_NULL == rb) || (SAF_NULL == rb_cpy))
	{
		aubRet = RB_ILLEGAL_DATA_PTR;
	}
	else
	{
		if((RB_INITED != rb->m_initFlag) || (RB_INITED != rb_cpy->m_initFlag))
		{
			aubRet = RB_UNINITED;
		}
		if((0 == rb_cpy->m_len) || (0 == rb->m_len))
		{
			aubRet = RB_EMPTY;
		}
	}

	if(RB_OK == aubRet)
	{
		if(rb_cpy->m_error == 1)
		{
			rb_cpy->m_phead = rb->m_phead;
			rb_cpy->m_error = 0; /*already change to normal status*/
		}
		else 
		{
			if(rb_cpy->m_phead != rb->m_phead)
			{
				if(rb_cpy->m_phead == rb_cpy->m_pdata)
				{
					if((*((rb_cpy->m_pdata + rb_cpy->m_max_size) -1))!= '\n')//when the header alreay to the head should check the buffer last data
					{
						rb_cpy->m_phead = rb->m_phead;
					}
				}
				else 
				{
					if((*(rb_cpy->m_phead-1)) !='\n')//check last data right or not
					{
						rb_cpy->m_phead = rb->m_phead;
					}
				}
			}
			if(rb_cpy->m_phead >= (rb_cpy->m_pdata + rb_cpy->m_max_size))//if header alreay to buffer outside error
			{
				rb_cpy->m_phead = rb->m_phead;
			}
		}
	}
	return aubRet;
}


