#include "p_apps.h"
#include "p_sip.h"
#include "v_task.h"
#include "my_mgcp.h"

#define TRANS_REQ_DATA_USED		0
#define TRANS_REQ_DATA_METHOD	1
#define TRANS_REQ_DATA_ID		2
#define TRANS_REQ_DATA_MSGLEN	6
#define TRANS_REQ_DATA_TIMER0	8
#define TRANS_REQ_DATA_TIMER1	10
#define TRANS_REQ_DATA_LEN		12

#define TRANS_RESP_DATA_USED	0
#define TRANS_RESP_DATA_ID		1
#define TRANS_RESP_DATA_MSGLEN	5
#define TRANS_RESP_DATA_TIMER	7
#define TRANS_RESP_DATA_LEN		8

#define TRANS_TIMER_COUNTER	0
#define TRANS_TIMER_TTL		1

#define TRANS_TIMER_T1		2
#define TRANS_TIMER_T2		16
#define TRANS_TIMER_T3		16

static DCHAR _iReqTransIndex;
static XCHAR _iRespTransIndex;

UCHAR _GetFreeReqTrans()
{
	DCHAR i;

	for (i = 0; i < MGCP_REQ_TRANS_NUM; i ++)
	{
		SdramReadData((USHORT)(PROTOCOL_SDRAM_POS+i + MGCP_REQ_TRANS_SDRAM_LO));
		if (!X_VAL(Sdram_pDataCache, TRANS_REQ_DATA_USED))
		{
			return i;
		}
	}

	i = _iReqTransIndex;
	_iReqTransIndex ++;
	if (_iReqTransIndex == MGCP_REQ_TRANS_NUM)
		_iReqTransIndex = 0;
	return i;
}

UCHAR _GetFreeRespTrans()
{
	DCHAR i;

	for (i = 0; i < MGCP_RESP_TRANS_NUM; i ++)
	{
		SdramReadData((USHORT)(PROTOCOL_SDRAM_POS+i + MGCP_RESP_TRANS_SDRAM_LO));
		if (!X_VAL(Sdram_pDataCache, TRANS_RESP_DATA_USED))
		{
			return i;
		}
	}

	i = _iRespTransIndex;
	_iRespTransIndex ++;
	if (_iRespTransIndex == MGCP_RESP_TRANS_NUM)
		_iRespTransIndex = 0;
	return i;
}

void _LoadReqTrans(UCHAR iTransNo, PXCHAR pTransData)
{
	SdramReadData((USHORT)(PROTOCOL_SDRAM_POS+iTransNo + MGCP_REQ_TRANS_SDRAM_LO));
	p_memcpy_x2x(pTransData, (PXCHAR)Sdram_pDataCache, TRANS_REQ_DATA_LEN);
}

void _LoadRespTrans(UCHAR iTransNo, PXCHAR pTransData)
{
	SdramReadData((USHORT)(PROTOCOL_SDRAM_POS+iTransNo + MGCP_RESP_TRANS_SDRAM_LO));
	p_memcpy_x2x(pTransData, (PXCHAR)Sdram_pDataCache, TRANS_RESP_DATA_LEN);
}

void _FreeReqTrans(UCHAR iTransNo)
{
	X_VAL(Sdram_pDataCache, TRANS_REQ_DATA_USED) = 0;
	SdramWriteData((USHORT)(PROTOCOL_SDRAM_POS+iTransNo + MGCP_REQ_TRANS_SDRAM_LO), TRANS_REQ_DATA_LEN);
}

void _FreeRespTrans(UCHAR iTransNo)
{
	X_VAL(Sdram_pDataCache, TRANS_RESP_DATA_USED) = 0;
	SdramWriteData((USHORT)(PROTOCOL_SDRAM_POS+iTransNo + MGCP_RESP_TRANS_SDRAM_LO), TRANS_RESP_DATA_LEN);
}
/**********************************************************************************
 **** Transaction interface functions *********************************************
 **********************************************************************************/
void MgcpTransInit()
{
	DCHAR i;

	X_VAL(Sdram_pDataCache, TRANS_REQ_DATA_USED) = 0;
	for (i = MGCP_REQ_TRANS_SDRAM_LO; i < (MGCP_REQ_TRANS_SDRAM_LO + MGCP_REQ_TRANS_NUM); i ++)
	{
		SdramWriteData((USHORT)(PROTOCOL_SDRAM_POS+i), TRANS_REQ_DATA_LEN);
	}
	_iReqTransIndex = 0;

	X_VAL(Sdram_pDataCache, TRANS_RESP_DATA_USED) = 0;
	for (i = MGCP_RESP_TRANS_SDRAM_LO; i < (MGCP_RESP_TRANS_SDRAM_LO + MGCP_RESP_TRANS_NUM); i ++)
	{
		SdramWriteData((USHORT)(PROTOCOL_SDRAM_POS+i), TRANS_RESP_DATA_LEN);
	}
	_iRespTransIndex = 0;
}

void MgcpTransSendReq(ULONG iTransId, UCHAR iMethod)
{
	DCHAR iTransNo;
	PXCHAR_D pTransData;

	Mgcp_iSendLen = p_line_get_len();

	iTransNo = _GetFreeReqTrans();

	// Save retransmit packet
	SdramSaveAll((USHORT)(PROTOCOL_SDRAM_POS+ (iTransNo << 1) + MGCP_REQ_TRANS_RETRANSMIT), (PXCHAR)Adapter_pSendUdpData);

	// Save transaction info
	pTransData = (PXCHAR)Sdram_pDataCache;
	pTransData[TRANS_REQ_DATA_USED] = 1;
	pTransData[TRANS_REQ_DATA_METHOD] = iMethod;
	ULONG2PUCHAR(iTransId, (PUCHAR)(PXCHAR)(pTransData + TRANS_REQ_DATA_ID));
	USHORT2PXCHAR(Mgcp_iSendLen, (PXCHAR)(pTransData + TRANS_REQ_DATA_MSGLEN));
	// timer 0
	pTransData[TRANS_REQ_DATA_TIMER0 + TRANS_TIMER_COUNTER] = 0;
	pTransData[TRANS_REQ_DATA_TIMER0 + TRANS_TIMER_TTL] = TRANS_TIMER_T1;
	// timer 1
	pTransData[TRANS_REQ_DATA_TIMER1 + TRANS_TIMER_COUNTER] = 0;
	pTransData[TRANS_REQ_DATA_TIMER1 + TRANS_TIMER_TTL] = TRANS_TIMER_T2;
	SdramWriteData((USHORT)(PROTOCOL_SDRAM_POS+iTransNo + MGCP_REQ_TRANS_SDRAM_LO), TRANS_REQ_DATA_LEN);

	MgcpSendReqData();
}

void MgcpTransSendResp(ULONG iTransId)
{
	DCHAR iTransNo;
	PXCHAR_D pTransData;
	
	Mgcp_iSendLen = p_line_get_len();
	if (Mgcp_iSendLen < (USHORT)(512 - UDP_DATA))
	{
		iTransNo = _GetFreeRespTrans();
		// Save retransmit packet
		SdramSaveAll((USHORT)(PROTOCOL_SDRAM_POS+ (iTransNo << 1) + MGCP_RESP_TRANS_RETRANSMIT), (PXCHAR)Adapter_pSendUdpData);
		// Save transaction info
		pTransData = (PXCHAR)Sdram_pDataCache;
		pTransData[TRANS_RESP_DATA_USED] = 1;
		ULONG2PUCHAR(iTransId, (PUCHAR)(PXCHAR)(pTransData + TRANS_RESP_DATA_ID));
		USHORT2PXCHAR(Mgcp_iSendLen, (PXCHAR)(pTransData + TRANS_RESP_DATA_MSGLEN));
		// timer 0
		pTransData[TRANS_RESP_DATA_TIMER + TRANS_TIMER_COUNTER] = 0;
		pTransData[TRANS_RESP_DATA_TIMER + TRANS_TIMER_TTL] = TRANS_TIMER_T3;
		SdramWriteData((USHORT)(PROTOCOL_SDRAM_POS+iTransNo + MGCP_RESP_TRANS_SDRAM_LO), TRANS_RESP_DATA_LEN);
	}

	MgcpSendRespData();
}

BOOLEAN MgcpTransRecvReq(ULONG iTransId)
{
	DCHAR i;
	XCHAR pTransData[TRANS_RESP_DATA_LEN];

	for (i = 0; i < MGCP_RESP_TRANS_NUM; i ++)
	{
		_LoadRespTrans(i, pTransData);
		if (pTransData[TRANS_RESP_DATA_USED] && PXCHAR2ULONG((PXCHAR)(pTransData + TRANS_RESP_DATA_ID)) == iTransId)
		{
			Mgcp_iSendLen = PXCHAR2USHORT((PXCHAR)(pTransData + TRANS_RESP_DATA_MSGLEN));
			MgcpRxRespPacket(i);
			return TRUE;
		}
	}

	return FALSE;
}

UCHAR MgcpTransRecvResp(ULONG iTransId)
{
	DCHAR i;
	XCHAR pTransData[TRANS_REQ_DATA_LEN];

	for (i = 0; i < MGCP_REQ_TRANS_NUM; i ++)
	{
		_LoadReqTrans(i, pTransData);
		if (pTransData[TRANS_REQ_DATA_USED] && PXCHAR2ULONG((PXCHAR)(pTransData + TRANS_REQ_DATA_ID)) == iTransId)
		{
			if (Mgcp_iRecvMsgType != 100)
			{
				_FreeReqTrans(i);
			}
			return pTransData[TRANS_REQ_DATA_METHOD];
		}
	}
	return MGCP_VERB_UNKNOWN;
}

void MgcpTransFree(ULONG iTransId)
{
	DCHAR i;
	XCHAR pTransData[TRANS_RESP_DATA_LEN];

	for (i = 0; i < MGCP_RESP_TRANS_NUM; i ++)
	{
		_LoadRespTrans(i, pTransData);
		if (pTransData[TRANS_RESP_DATA_USED] && PXCHAR2ULONG((PXCHAR)(pTransData + TRANS_RESP_DATA_ID)) == iTransId)
		{
			_FreeRespTrans(i);
		}
	}
}

void MgcpTransHandleTimer()
{
	DCHAR iTransNo;
	XCHAR pTransData[TRANS_REQ_DATA_LEN];

	for (iTransNo = 0; iTransNo < MGCP_REQ_TRANS_NUM; iTransNo ++)
	{
		_LoadReqTrans(iTransNo, pTransData);
		if (!pTransData[TRANS_REQ_DATA_USED])	
			continue;
		pTransData[TRANS_REQ_DATA_TIMER1 + TRANS_TIMER_COUNTER] ++;
		if (pTransData[TRANS_REQ_DATA_TIMER1 + TRANS_TIMER_COUNTER] > pTransData[TRANS_REQ_DATA_TIMER1 + TRANS_TIMER_TTL])
		{
			_FreeReqTrans(iTransNo);
			MgcpHandleTspError(pTransData[TRANS_REQ_DATA_METHOD]);
			continue;
		}
		pTransData[TRANS_REQ_DATA_TIMER0 + TRANS_TIMER_COUNTER] ++;
		if (pTransData[TRANS_REQ_DATA_TIMER0 + TRANS_TIMER_COUNTER] > pTransData[TRANS_REQ_DATA_TIMER0 + TRANS_TIMER_TTL])
		{
			Mgcp_iSendLen = PXCHAR2USHORT((PXCHAR)(pTransData + TRANS_REQ_DATA_MSGLEN));
			MgcpRxReqPacket(iTransNo);
			pTransData[TRANS_REQ_DATA_TIMER0 + TRANS_TIMER_COUNTER] = 0;
		}
		p_memcpy_x2x((PXCHAR)Sdram_pDataCache, pTransData, TRANS_REQ_DATA_LEN);
		SdramWriteData((USHORT)(PROTOCOL_SDRAM_POS+iTransNo + MGCP_REQ_TRANS_SDRAM_LO), TRANS_REQ_DATA_LEN);
	}
	
	for (iTransNo = 0; iTransNo < MGCP_RESP_TRANS_NUM; iTransNo ++)
	{
		_LoadRespTrans(iTransNo, pTransData);
		if (!pTransData[TRANS_RESP_DATA_USED])	
			continue;
		pTransData[TRANS_RESP_DATA_TIMER + TRANS_TIMER_COUNTER] ++;
		if (pTransData[TRANS_RESP_DATA_TIMER + TRANS_TIMER_COUNTER] > pTransData[TRANS_RESP_DATA_TIMER + TRANS_TIMER_TTL])
		{
			_FreeRespTrans(iTransNo);
		}
	}
}