#include "p_apps.h"
#include "v_task.h"
#include "autoprov.h"

#ifndef OEM_NET2PHONE

#define TFTP_INTERVAL_TIME	2
#define TFTP_MAX_RETRY		4
#define TFTP_BLOCK_SIZE		512

#define	TFTP_OPCODE_PTR			0
#define	TFTP_FILENAME_PTR		2
#define TFTP_BLOCK_PTR			2
#define	TFTP_DATA_PTR			4

#define	TFTP_OPCODE_READ		1
#define	TFTP_OPCODE_WRITE		2
#define	TFTP_OPCODE_DATA		3
#define	TFTP_OPCODE_ACK			4
#define	TFTP_OPCODE_ERROR		5
#define	TFTP_OPCODE_OACK		6

static BOOLEAN _bTftpLoading;
static XSHORT _iTftpLocalPort;

static XCHAR _iTimer, _iRetries;
static XSHORT _iBlockNum;
static XCHAR _iIndexHigh, _iIndexLow;

void _SendAckPacket(BOOLEAN bOK)
{
	UdpOpen(Adapter_pReceiveIPAddress, PXCHAR2USHORT((PXCHAR)Adapter_pReceivePacket), _iTftpLocalPort, TFTP_SDRAM_LO);

	X_VAL(Adapter_pSendUdpData, TFTP_OPCODE_PTR) = 0;
	X_VAL(Adapter_pSendUdpData, TFTP_OPCODE_PTR+1) = bOK ? TFTP_OPCODE_ACK : TFTP_OPCODE_ERROR;
	USHORT2PXCHAR((USHORT)_iBlockNum, (PXCHAR)(Adapter_pSendUdpData+TFTP_BLOCK_PTR));

	if (bOK)
	{
		_iBlockNum ++;
	}

	UdpSend(4, TFTP_SDRAM_LO);
	_iTimer = 0;
}

void _TftpGetFile()
{
	PXCHAR_D pCur;
	DCHAR iLen;

	pCur = (PXCHAR)Adapter_pSendUdpData;

	_iTftpLocalPort = (USHORT)(TFTP_SRC_PORT + p_rand_char());
	UdpOpen(Upgrade_pServerIP, TFTP_SERVER_PORT, _iTftpLocalPort, TFTP_SDRAM_LO);

	SdramReadData(OPTIONS_SDRAM_POS+UPGRADE_FILENAME_LO);		// File name is in Sdram_pDataCache
	iLen = p_strlen_x((PXCHAR)Sdram_pDataCache);

	X_VAL(Adapter_pSendUdpData, TFTP_OPCODE_PTR) = 0;
	X_VAL(Adapter_pSendUdpData, TFTP_OPCODE_PTR+1) = TFTP_OPCODE_READ;
	pCur += TFTP_FILENAME_PTR;
	p_strcpy_x2x(pCur, (PXCHAR)Sdram_pDataCache);
	pCur += iLen + 1;
	p_strcpy_c2x(pCur, (PCCHAR)"octet");
	iLen += 9;	

	OutputString(IDS_TFTP_SEND);
	UdpSend(iLen, TFTP_SDRAM_LO);
	_iBlockNum = 1;
	CreateUpgradeFile();
}

BOOLEAN TftpRun()
{
	DCHAR iTftpOpcode;
	PXCHAR_D pCur;
	BOOLEAN bFinished;

	if (Adapter_iReceiveUdpPort != _iTftpLocalPort)	return FALSE;

	iTftpOpcode = X_VAL(Adapter_pReceiveUdpData, TFTP_OPCODE_PTR+1);

	if (!X_VAL(Adapter_pReceiveUdpData, TFTP_OPCODE_PTR))
	{
		if (iTftpOpcode == TFTP_OPCODE_DATA)
		{
			// data packet, check blk seq
			if (_iBlockNum == PXCHAR2USHORT((PXCHAR)(Adapter_pReceiveUdpData+TFTP_BLOCK_PTR)))
			{
				OutputVal(_iBlockNum, IDS_TFTP_BLOCK);
				pCur = (PXCHAR)(Adapter_pReceiveUdpData+TFTP_DATA_PTR);
				Adapter_iReceiveLen -= TFTP_DATA_PTR;
				bFinished = FALSE;
				if (Adapter_iReceiveLen < TFTP_BLOCK_SIZE)
				{
					bFinished = TRUE;
				}
				while (Adapter_iReceiveLen >= 256)
				{
					SoloFileWrite(pCur, (UCHAR)256);
					pCur += 256;
					Adapter_iReceiveLen -= 256;
				}

				if (Adapter_iReceiveLen && Adapter_iReceiveLen < 256)
				{
					SoloFileWrite(pCur, (UCHAR)Adapter_iReceiveLen);
				}
				DisplayFileStatus();

				_iRetries = 0;
				_SendAckPacket(TRUE);

				if (bFinished)
				{
					OutputString(IDS_TFTP_FINISHED);
					SoloFileClose();
					if (Upgrade_iType == UPGRADE_GET_SET)
					{
						ProvHandleSetFile();
						if (Upgrade_iType != UPGRADE_GET_SET)
						{
							_TftpGetFile();
						}
						else
						{
							CloseFileAndCheckLimit();
						}
					}
					else
					{
						ProvStartUpgrade();
					}
				}
			}
			else
			{
				_SendAckPacket(FALSE);
			}
		}
		else if (iTftpOpcode == TFTP_OPCODE_OACK)
		{
			// ack packet, blksize ok?
			OutputString(IDS_TFTP_OACK);
			_iBlockNum = 0;
			_SendAckPacket(TRUE);
		}
		else if (iTftpOpcode == TFTP_OPCODE_ERROR)
		{
			OutputString(IDS_TFTP_ERROR);
			CloseFileAndCheckLimit();
		}
	}

	return TRUE;
}

void TftpInitialize()
{
	_iTimer = 0;
	_iRetries = 0;
	_iBlockNum = 0;
	_iTftpLocalPort = 0;
}

void TftpUpgrade(UCHAR iType)
{
	Upgrade_iType = iType;
	ProvGetFileName();
	_TftpGetFile();
}

void TftpHandleTimer()
{
	if (!_iTftpLocalPort)	return;

	_iTimer ++;
	if (_iTimer >= TFTP_INTERVAL_TIME)
	{
		_iRetries ++;
		_iTimer = 0;
		if (_iRetries >= TFTP_MAX_RETRY)
		{
			OutputString(IDS_TFTP_FAILED);
			CloseFileAndCheckLimit();
		}
		else
		{
			OutputString(IDS_TFTP_RETRY);
			if (_iBlockNum)
			{
				_iBlockNum --;
				_SendAckPacket(TRUE);
			}
		}
	}
}

#endif

