#include "PalmType.h"
#include "Palm1lib.h"
#include "p_tcpip.h"
#include "my_iax2.h"
#include "p_iax2.h"
#include "v_task.h"
#include "port.h"

#define IAX2_FRAME_USED		0
#define IAX2_FRAME_SESSION	1
#define IAX2_FRAME_OSEQNO	2
#define IAX2_FRAME_SIZE		3
#define IAX2_FRAME_RETRY	5
#define IAX2_FRAME_TIMER	6
#define IAX2_FRAME_LEN		7		


static CCHAR _cRetryTTL[IAX_MAX_RETRIES] = {1, 2, 2, 4, 4};

static XCHAR _pFrameInfo[IAX2_FRAME_LEN];


void iax2_frame_startup()
{
	DCHAR i;
	
	p_memset_x((PXCHAR)Sdram_pDataCache, 0, IAX2_FRAME_LEN);
	for (i = 0; i < IAX2_FRAME_NUM; i ++)
	{
		SdramWriteData((USHORT)(PROTOCOL_SDRAM_POS+IAX2_FRAMEINFO_SDRAM_LO + i), IAX2_FRAME_LEN);
	}
}

UCHAR _frame_new()
{
	DCHAR i;
	for (i = 0; i < IAX2_FRAME_NUM; i ++)
	{
		SdramReadData((USHORT)(PROTOCOL_SDRAM_POS+IAX2_FRAMEINFO_SDRAM_LO + i));
		if (!X_VAL(Sdram_pDataCache, IAX2_FRAME_USED))
			return i;
	}
	return IAX2_FRAME_NUM;
}

void _frame_free(UCHAR iIndex)
{
	p_memset_x((PXCHAR)Sdram_pDataCache, 0, IAX2_FRAME_LEN);
	SdramWriteData((USHORT)(PROTOCOL_SDRAM_POS+IAX2_FRAMEINFO_SDRAM_LO + iIndex), IAX2_FRAME_LEN);
}

void _frame_saveinfo(UCHAR iIndex)
{
	p_memcpy_x2x((PXCHAR)Sdram_pDataCache, _pFrameInfo, IAX2_FRAME_LEN);
	SdramWriteData((USHORT)(PROTOCOL_SDRAM_POS+IAX2_FRAMEINFO_SDRAM_LO + iIndex), IAX2_FRAME_LEN);
}

void _frame_loadinfo(UCHAR iIndex)
{
	SdramReadData((USHORT)(PROTOCOL_SDRAM_POS+IAX2_FRAMEINFO_SDRAM_LO + iIndex));
	p_memcpy_x2x(_pFrameInfo, (PXCHAR)Sdram_pDataCache, IAX2_FRAME_LEN);
}

void _frame_retry(UCHAR iIndex)
{
	DSHORT iLen;
	
	iLen = PXCHAR2USHORT((PXCHAR)(_pFrameInfo + IAX2_FRAME_SIZE));
	SdramCopyEthernetFrame((USHORT)(PROTOCOL_SDRAM_POS+IAX2_FRAMEDATA_SDRAM_LO + iIndex * 6), (PXCHAR)Adapter_pSendUdpData, iLen);
	// here need to change the retransmission flag
	X_VAL(Adapter_pSendUdpData, IAX_FULLFR_DCALLNO) |= 0x80;
	iax2_dbg_send(iLen, _pFrameInfo[IAX2_FRAME_SESSION]);
}

void iax2_frame_save(UCHAR iSession, USHORT iLen, UCHAR iOSeqNo)
{
	DCHAR iIndex;

	if (!iLen)	return;

	iIndex = _frame_new();
	if (iIndex == IAX2_FRAME_NUM)
	{
		DebugCString((PCCHAR)"No more frame available");
		return;
	}
	_pFrameInfo[IAX2_FRAME_USED] = 1;
	_pFrameInfo[IAX2_FRAME_SESSION] = iSession;
	_pFrameInfo[IAX2_FRAME_OSEQNO] = iOSeqNo;
	USHORT2PXCHAR(iLen, (PXCHAR)(_pFrameInfo + IAX2_FRAME_SIZE));
	_pFrameInfo[IAX2_FRAME_RETRY] = 0;
	_pFrameInfo[IAX2_FRAME_TIMER] = 0;
	_frame_saveinfo(iIndex);
	SdramSaveEthernetFrame((USHORT)(PROTOCOL_SDRAM_POS+IAX2_FRAMEDATA_SDRAM_LO + iIndex * 6), (PXCHAR)Adapter_pSendUdpData, iLen);
}


void iax2_frame_handle_timer()
{
	DCHAR i;

	for (i = 0; i < IAX2_FRAME_NUM; i ++)
	{
		_frame_loadinfo(i);
		if (!_pFrameInfo[IAX2_FRAME_USED])
		{
			continue;
		}
		_pFrameInfo[IAX2_FRAME_TIMER] ++;
		if (_pFrameInfo[IAX2_FRAME_TIMER] > _cRetryTTL[_pFrameInfo[IAX2_FRAME_RETRY]])
		{
			_pFrameInfo[IAX2_FRAME_RETRY] ++;
			if (_pFrameInfo[IAX2_FRAME_RETRY] >= IAX_MAX_RETRIES)
			{
				// time out
				iax2_session_rxerror(_pFrameInfo[IAX2_FRAME_SESSION]);
				_frame_free(i);
			}
			else
			{
				_frame_retry(i);
				_pFrameInfo[IAX2_FRAME_TIMER] = 0;
				_frame_saveinfo(i);
			}
		}
		else
		{
			_frame_saveinfo(i);
		}
	}
}

void iax2_frame_cancel(UCHAR iSession, UCHAR iOSeqNo)
{
	DCHAR i;
	for (i = 0; i < IAX2_FRAME_NUM; i ++)
	{
		_frame_loadinfo(i);
		if (!_pFrameInfo[IAX2_FRAME_USED])
		{
			continue;
		}
		if (_pFrameInfo[IAX2_FRAME_SESSION] == iSession && _pFrameInfo[IAX2_FRAME_OSEQNO] == iOSeqNo)
		{
			_frame_free(i);
		}
	}
}

void iax2_frame_txacked(UCHAR iSession)
{
	DCHAR i;

	for (i = 0; i < IAX2_FRAME_NUM; i ++)
	{
		_frame_loadinfo(i);
		if (!_pFrameInfo[IAX2_FRAME_USED])
		{
			continue;
		}
		if (_pFrameInfo[IAX2_FRAME_SESSION] == iSession)
		{
			SdramCopyEthernetFrame((USHORT)(PROTOCOL_SDRAM_POS+IAX2_FRAMEDATA_SDRAM_LO + i * 6), (PXCHAR)Adapter_pSendUdpData, IAX_FULLFR_DATA);
			// here need to change the retransmission flag
			if (X_VAL(Adapter_pSendUdpData, IAX_FULLFR_TYPE) == AST_FRAME_IAX && X_VAL(Adapter_pSendUdpData, IAX_FULLFR_CSUB) == IAX_COMMAND_TXCNT)
			{
				_frame_free(i);
			}
		}
	}
}

void iax2_frame_rexmit(UCHAR iSession, UCHAR iOSeqNo)
{
	DCHAR i;
	for (i = 0; i < IAX2_FRAME_NUM; i ++)
	{
		_frame_loadinfo(i);
		if (!_pFrameInfo[IAX2_FRAME_USED])
		{
			continue;
		}
		if (_pFrameInfo[IAX2_FRAME_SESSION] == iSession && _pFrameInfo[IAX2_FRAME_OSEQNO] >= iOSeqNo)
		{
			_frame_retry(i);
			_pFrameInfo[IAX2_FRAME_TIMER] = 0;
			_pFrameInfo[IAX2_FRAME_RETRY] ++;
			_frame_saveinfo(i);
		}
	}
}

void iax2_frame_free(UCHAR iSession)
{
	DCHAR i;
	for (i = 0; i < IAX2_FRAME_NUM; i ++)
	{
		_frame_loadinfo(i);
		if (!_pFrameInfo[IAX2_FRAME_USED])
		{
			continue;
		}
		if (_pFrameInfo[IAX2_FRAME_SESSION] == iSession)
		{
			_frame_free(i);
		}
	}
}