/* Data packet class */

#include	<stdio.h>
#include    "ccnet_io.h"
#include	"ErrCode.h"



//===========================================================================
//-----------Packet handling class definition---------
class CPacket
{
public:
	//---constructor & destructor---
	CPacket(unsigned long bufsize);
	~CPacket();
	
	
	//-----Add a CAMAC frame
	int AddFrame(unsigned char N, unsigned char A, unsigned char F, unsigned long W);
	//-----Add a DAQ-control frame
	int AddFrame(unsigned char opCode);
	
	
	//---Execution start
	int Go(unsigned char mode=0);	//mode 0:auto_select, 1:pio, 2:dma, 3:dma_seq

	int WaitIntrFrm(unsigned long time);	//waiting for INTR frame.
	int WaitIntrFrm(unsigned long time, unsigned long match);	//wait with MATCH PATTERN.
	
	
	//-----Read a frame
	int ReadFrame(long index);	//examine which type of frame
	int ReadFrame(long index, unsigned long* code, unsigned long* data);	//frame copy...
	
	
	//----tell you how many frames for Tx/Rx(this is NOT a FIFO COUNTER.)
	int HowManyFrames(unsigned char type=0);	//type 0:buffersize, 1:TxFrames, 2:RxFrames, 3:IrFrames
	
	//----Clear RxFrm counter
	int ResetRxFrmCnt();
	


private:
	unsigned char nHdr;					//holds frame header
	struct FRAME *pCmdFrm, *pRplFrm, *pIntFrm;
	unsigned long nBufSize;
	unsigned long nTxFrmCnt, nRxFrmCnt, nIrFrmCnt;	//Frame amount which are "outside of FIFO"
	
};





//===========================================================================
//-----------Packet handling class body---------
CPacket::CPacket(unsigned long bufsize)
{
	nBufSize = bufsize;
	pCmdFrm = new struct FRAME[nBufSize];
	pRplFrm = new struct FRAME[nBufSize];
	pIntFrm = new struct FRAME[nBufSize];
	nTxFrmCnt = 0;
	nRxFrmCnt = 0;
	nIrFrmCnt = 0;
}

CPacket::~CPacket()
{
	delete [] pCmdFrm;
	delete [] pRplFrm;
	delete [] pIntFrm;
}


//------------------Add a CAMAC frame------------------
int CPacket::AddFrame(unsigned char N, unsigned char A, unsigned char F, unsigned long W)
{
	if (nTxFrmCnt > (nBufSize-1) ) return AF_ER_NOSPACE;
	
	if ( nTxFrmCnt )	nHdr = 0x80;
	else				nHdr = 0xc0;
	
	pCmdFrm[nTxFrmCnt].code = (nHdr<<24) | (N<<16) | (A<<8) | F ;
	pCmdFrm[nTxFrmCnt].data = 0xffffff & W;

	nTxFrmCnt++;
	return AF_DONE;
}


//------------------Add a DAQ-control frame------------------
int CPacket::AddFrame(unsigned char opCode)
{

	if (nTxFrmCnt > (nBufSize-1) ) return AF_ER_NOSPACE;

	if ( nTxFrmCnt )	nHdr = 0x90;
	else				nHdr = 0xd0;
	
	pCmdFrm[nTxFrmCnt].code = (nHdr<<24) | (opCode<<16);
	pCmdFrm[nTxFrmCnt].data = 0;

	nTxFrmCnt++;
	return AF_DONE;
}


//------------------Execution start(CAUTION: read amount = send amout)------------------
int CPacket::Go(unsigned char mode)	//mode 0: auto_select, 1:pio, 2:dma, 3:dma_seq
{
	if ( nTxFrmCnt==0 )	return GO_ER_NOFRM;

	pCmdFrm[nTxFrmCnt-1].code |= 0x20000000;	//set EPKT frag

	/* only PIO at present... */
	unsigned long i, rpl_cnt=0;
	
		
	for ( i=0; i<nTxFrmCnt; i++ )	//send compulsively until nTxFrmCnt
	{
		//PUT and then Get
		if ( put_frame(pCmdFrm[i]) )	return GO_ER_TXTOUT;

		while ( rpl_cnt < i+1 )
			if ( get_frame( &pRplFrm[nRxFrmCnt] )==0 )
			{
				rpl_cnt++;
				nRxFrmCnt++;
				if ( nRxFrmCnt > nBufSize )	return GO_ER_RXOVER;
			}
	}

	if ( rpl_cnt != nTxFrmCnt )	return GO_ER_RXTOUT;

	nTxFrmCnt =0;
	return GO_DONE;
}


//------------------waiting for INTR frame.------------------
int CPacket::WaitIntrFrm(unsigned long time)
{
	unsigned long wcnt=time;

	if ( nIrFrmCnt > nBufSize-1 )	return WI_ER_RXOVER;


	while ( get_intfrm( &pIntFrm[nIrFrmCnt] ) )
		if ( wcnt-- )	continue;
		else return WI_ER_TOUT;

	nIrFrmCnt++;
	return WI_DONE;
}


int CPacket::WaitIntrFrm(unsigned long time, unsigned long match)
{
	unsigned long wcnt=time;

	if ( nIrFrmCnt > nBufSize-1 )	return WI_ER_RXOVER;

	while ( get_intfrm( &pIntFrm[nIrFrmCnt] ) )
		if ( wcnt-- )	continue;
		else return WI_ER_TOUT;

	nIrFrmCnt++;
	if (pIntFrm[nIrFrmCnt-1].data == match)	return WI_DONE;
	else									return WI_ER_NOMATCH;
//	
	return -1;
}


//------------------Read rply frame ------------------
int CPacket::ReadFrame(long index)	//examine which type of frame
{
	if ( nRxFrmCnt==0 )	return RF_ER_NODATA;
	
	unsigned long idx;
	if ( index < 0)	idx = nRxFrmCnt-1;
	else			idx = index;
	if ( idx > nRxFrmCnt-1 ) return RF_ER_RANGEOUT;
	
	unsigned long src;
	src = pRplFrm[idx].code & 0x10000000;
	
	switch (src)
	{
		case (0x00000000) :	return RF_CAMAC;
		case (0x10000000) :	return RF_DAQCTRL;
		default :	return 0;
	}
	return 0;
}
//------------------------------------
int CPacket::ReadFrame(long index, unsigned long* code, unsigned long* data)	//frame copy...
{
	if ( nRxFrmCnt==0 )	return RF_ER_NODATA;
	
	unsigned long idx;
	if ( index < 0)	idx = nRxFrmCnt-1;
	else			idx = index;
	if ( idx > nRxFrmCnt-1 ) return RF_ER_RANGEOUT;

	*code = pRplFrm[idx].code;
	*data = pRplFrm[idx].data;
	
	return RF_DONE;
}


//------------------type 0:buffersize, 1:TxFrames, 2:RxFrames, 3:IrFrames------------------
int CPacket::HowManyFrames(unsigned char type)
{
	switch (type)
	{
		case 1:		return nTxFrmCnt;
		case 2:		return nRxFrmCnt;
		case 3:		return nIrFrmCnt;
		default :	return nBufSize;
	}
	return 0;
}


//------------------Clear RxFrm counter------------------
int CPacket::ResetRxFrmCnt()
{
	nRxFrmCnt = 0;
	return 0;
}

