/*-------------------------------------------------------------------------
   AR1688 main function copy right information

   Copyright (C) 2006-2009. Lin, Rongrong <woody@palmmicro.com>
                            Tang, Li      <tangli@palmmicro.com>
						    Li, Jing      <lijing@palmmicro.com>

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   This software is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-------------------------------------------------------------------------*/

#include "version.h"
#include "sfr_gpio.h"
#include "type.h"
#include "ar168.h"
#include "apps.h"
#include "core.h"
#include "tcpip.h"
#include "sha1.h"
#include "bank1.h"
#include "bank2.h"
#include "bank3.h"
#include "bank4.h"
#include "bank5.h"
#include "bank6.h"
#include "bank7.h"

#ifdef CALL_NONE
const UCHAR _cVersion[14] = {'V', 'e', 'r', ':', ' ', SOFT_VER_HIGH+'0', '.', SOFT_VER_LOW+'0', SOFT_VER_BUILD+'0', '.', ENG_BUILD_HIGH+'0', ENG_BUILD_MID+'0', ENG_BUILD_LOW+'0', 0};
#endif

TIME_T Sys_tmLocal;

// main function MUST be the first function in this module
void main()
{
	// Init orders are important, do NOT change! FlashInit need to be the first function called
	FlashInit();
	ChipInit();
	heap_init();	// call heap_init() right after FlashInit() and ChipInit;

#ifdef CALL_NONE
	KeyInit();		// detect * key for safe mode below, key.c is always in bank1!
#ifndef SYS_CHIP_PLUS
	rGPIO_A &= 0xfe;	//	GPIO_A0 On
#endif
#if !defined VER_AR168I && !defined VER_QX900W && !defined SLIC_79R70
	// do NOT change this! ar168d/ar168ds use GPIO_A2 as flash CS, need to be 0 to boot from primary flash
	// wt6104 use GPIO_A2 as read enable(0) and disable(1)
	rGPIO_A &= 0xfb;	// GPIO_A2 On
#endif
#ifdef RTL8019AS
	Ne2000InitStep1();
#endif
	LcdInit();
	LcdStart();
	LcdDisplay(_cVersion, 0);
#ifdef OEM_LCDTEST
	LcdFactoryTest();
#endif
#ifdef RTL8019AS
	if (DetectSafeRecoveryMode(200)) goto SafeMode;
	Ne2000InitStep2();
	if (DetectSafeRecoveryMode(2250)) goto SafeMode;		// wait 2 seconds for NE2000 cold boot
#elif defined DM9003EP || defined KSZ8842
	if (DetectSafeRecoveryMode(1)) goto SafeMode;
#endif
#ifndef SYS_CHIP_PLUS
	rGPIO_A |= 0x01;	// GPIO_A0 Off
#endif
	JumpMain();	// * key is not pressed, goto main program
SafeMode:
#ifdef RTL8019AS
	Delay2Seconds();
	Ne2000InitStep2();
	Delay2Seconds();
#endif
	OptionsInit();
#else
	LcdStart();
#endif
	UI_Init();

	FlashSetBankOffset(NET_BANK_OFFSET);
	NetInit();
	TftpInit();

#ifndef CALL_NONE
	srand(12);
	SntpInit();
	DnsInit();
#ifdef OEM_AUTOTEST
	DhcpdInit();
#endif

#ifdef CALL_SIP
	StunInit();
#endif

	FlashSetBankOffset(TCP_BANK_OFFSET);
	TcpInit();
//	FlashSetBankOffset(HTTP_BANK_OFFSET);
	HttpInit();

	FlashSetBankOffset(MENU_BANK_OFFSET);
	CallLogInit();

	FlashSetBankOffset(PROTOCOL_BANK_OFFSET);
#ifdef CALL_SIP
	SipInit();
	FlashSetBankOffset(SIPR_BANK_OFFSET);
	SiprInit();
#elif defined CALL_IAX2
	Iax2Init();
#endif	
	
	if (Sys_iIpType)
	{
		FlashSetBankOffset(NET_BANK_OFFSET);
		NetDiscover();
	}
	else
	{
		TaskStartProv();
		TaskStartApp();
	}
#endif	// CALL_NONE
	
	FlashSetBankOffset(UI_BANK_OFFSET);
#if defined SYS_UART || defined SYS_SPI
	SerialInit();	// Call SerialInit() before interrupt enabled in UI_Start() 
#endif
	UI_Start();

	do
	{
		if (_bTimer)	// 1 second timer
		{
			_bTimer = FALSE;

			FlashSetBankOffset(NET_BANK_OFFSET);
			NetTimer();
			
#ifndef CALL_NONE
//			CheckStack();
			
			if (Net_bConnected)
			{
				FlashSetBankOffset(TCP_BANK_OFFSET);
				TcpTimer();
//				FlashSetBankOffset(HTTP_BANK_OFFSET);
//				HttpTimer();
#ifdef OEM_INNOMEDIA
				HttpcTimer();
#endif
				HttpdTimer();

				FlashSetBankOffset(PROTOCOL_BANK_OFFSET);
#ifdef CALL_IAX2
				Iax2Timer();
#elif defined CALL_SIP
				SipTimer();
#endif
			}
#endif

			FlashSetBankOffset(UI_BANK_OFFSET);
			UI_Timer();

#ifndef CALL_NONE
			Sys_tmLocal.iSec ++;
			if (Sys_tmLocal.iSec == 60) 
			{
				if (Net_bConnected)
				{
					FlashSetBankOffset(HTTP_BANK_OFFSET);
					HttpcMinuteTimer();
				}

#ifdef OEM_BT2008
				FlashSetBankOffset(MENU_BANK_OFFSET);
				CallLogTimer();
#endif

				FlashSetBankOffset(UI_BANK_OFFSET);
				UI_MinuteTimer();
			}
#endif
		}

		FlashSetBankOffset(UI_BANK_OFFSET);
#if defined SYS_UART || defined SYS_SPI
		SerialRun();
#endif
		UI_Run();

		FlashSetBankOffset(NET_BANK_OFFSET);
#ifdef RTL8019AS
		Ne2000Run();	// ReadPacket() in BANK2
#elif defined DM9003EP
		Dm9000Run();	// HandlePacket() in BANK2
#elif defined KSZ8842
		Ksz8842Run();	// HandlePacket() in BANK2
#endif

	} while (1);
}

#ifndef CALL_NONE

void TaskFrameTimer()
{
	UCHAR iOrg;

	// remember to set page here before call call-back
	iOrg = FlashSetBankOffset(PROTOCOL_BANK_OFFSET);
#ifdef CALL_IAX2
	Iax2FrameTimer();
#elif defined CALL_SIP
	SipFrameTimer();
#endif
//	Sys_sDebug ++;
	FlashSetBank(iOrg);
}

void TaskOutgoingData(UCHAR iLen)
{
	UCHAR iOrg;

	// remember to set page here before call call-back
	iOrg = FlashSetBankOffset(PROTOCOL_BANK_OFFSET);
#ifdef CALL_IAX2
	Iax2SendVoice(iLen);
#elif defined CALL_SIP
	SipSendVoice(iLen);
#endif
	FlashSetBank(iOrg);
}

void TaskIncomingData(USHORT sLen, PCHAR pBuf, UCHAR iType)
{
	UCHAR iOrg;

	iOrg = FlashSetBankOffset(UI_BANK_OFFSET);
	DspHandleData(sLen, pBuf, iType);
	FlashSetBank(iOrg);
}

void TaskMiniRun()
{
#ifdef RTL8019AS
	UCHAR iOrg;

	iOrg = FlashSetBankOffset(UI_BANK_OFFSET);
	DspRun(TRUE);
	FlashSetBankOffset(NET_BANK_OFFSET);
	Ne2000MiniRun();
	FlashSetBank(iOrg);
#endif
}

#ifdef OEM_INNOMEDIA
void TaskRC4Init(PCHAR pKey, UCHAR iKeyLen)
{
	UCHAR iOrg;

	iOrg = FlashSetBankOffset(MD5_BANK_OFFSET);
	RC4Init(pKey, iKeyLen);
	FlashSetBank(iOrg);
}

void TaskRC4Calc(PCHAR pDst, PCHAR pSrc, USHORT sLen)
{
	UCHAR iOrg;
	iOrg = FlashSetBankOffset(MD5_BANK_OFFSET);
	RC4Calc(pDst, pSrc, sLen);
	FlashSetBank(iOrg);
}

void TaskGenKey(PCHAR P, PCHAR S, USHORT c, PCHAR DK, UCHAR dkLen)
{
	UCHAR iOrg;
	iOrg = FlashSetBankOffset(MD5_BANK_OFFSET);
	pbkdf2_sha1(P, S, c, DK, dkLen);
	FlashSetBank(iOrg);
}
#endif

void TaskMD5GenValue(PCHAR pDst, PCHAR pSrc, UCHAR iLen)
{
	UCHAR iOrg;

	iOrg = FlashSetBankOffset(MD5_BANK_OFFSET);
	MD5GenValue(pDst, pSrc, iLen);
	FlashSetBank(iOrg);
}

BOOLEAN TaskMapMatch(PCHAR pNumber)
{
	UCHAR iOrg;
	BOOLEAN bRet;

	iOrg = FlashSetBankOffset(DIGITMAP_BANK_OFFSET);
	bRet = MapMatch(pNumber);
	FlashSetBank(iOrg);

	return bRet;
}

// may need to call line_backup() and line_restore before and after calling this function
void TaskHttpDigest(PCHAR pDst, PCHAR pAuthData, PCHAR pUri, PCHAR pAccount, PCHAR pPassword, PCHAR pMethod)
{
	UCHAR iOrg;

	iOrg = FlashSetBankOffset(AUTH_BANK_OFFSET);
	http_digest(pDst, pAuthData, pUri, pAccount, pPassword, pMethod);
	FlashSetBank(iOrg);
}

void TaskStartProv()
{
	UCHAR iOrg;

	iOrg = FlashSetBankOffset(HTTP_BANK_OFFSET);
	HttpcStart();
	FlashSetBank(iOrg);
}

void TaskStartApp()
{
	UCHAR iOrg;

	iOrg = FlashSetBankOffset(NET_BANK_OFFSET);
	SntpStart(TRUE);
	FlashSetBank(iOrg);
}

#ifdef CALL_SIP
void TaskStunMap(UCHAR iTask, UDP_SOCKET pSocket)
{
	UCHAR iOrg;

	iOrg = FlashSetBankOffset(NET_BANK_OFFSET);
	StunMap(iTask, pSocket);
	FlashSetBank(iOrg);
}

void TaskStunDone(PCHAR pMappedAddr, USHORT sMappedPort, UCHAR iTask)
{
	UCHAR iOrg;

	iOrg = FlashSetBankOffset(PROTOCOL_BANK_OFFSET);
	SipStunDone(pMappedAddr, sMappedPort, iTask);
	FlashSetBankOffset(NET_BANK_OFFSET);
	StunInit();
	FlashSetBank(iOrg);
}

BOOLEAN TaskStunRun(UDP_SOCKET pUcb)
{
	BOOLEAN bVal;
	UCHAR iOrg;

	iOrg = FlashSetBankOffset(NET_BANK_OFFSET);
	bVal = StunRun(pUcb);
	FlashSetBank(iOrg);

	return bVal;
}
#endif

void TaskHandleEvent(UCHAR iEvent, USHORT sParam)
{
	UCHAR iOrg;

	iOrg = FlashSetBankOffset(PROTOCOL_BANK_OFFSET);
#ifdef CALL_IAX2
	Iax2HandleEvent(iEvent, sParam);
#elif defined CALL_SIP
	SipHandleEvent(iEvent, sParam);
#else
	iEvent;
	sParam;
#endif
	FlashSetBank(iOrg);
}

USHORT TaskGetCallInfo(UCHAR iType)
{
	UCHAR iOrg;
	USHORT sVal;

	iOrg = FlashSetBankOffset(PROTOCOL_BANK_OFFSET);
#ifdef CALL_IAX2
	sVal = Iax2GetCallInfo(iType);
#elif defined CALL_SIP
	sVal = SipGetCallInfo(iType);
#else
	sVal = 0;
#endif
	FlashSetBank(iOrg);

	return sVal;
}

USHORT TaskHttpEvent(UCHAR iEvent, USHORT sParam)
{
	UCHAR iOrg;
	USHORT sVal;

	iOrg = FlashSetBankOffset(MENU_BANK_OFFSET);
	sVal = HttpHandleEvent(iEvent, sParam);
	FlashSetBank(iOrg);

	return sVal;
}

void TaskMenuEvent(UCHAR iEvent)
{
#ifdef SYS_LCD
	UCHAR iOrg;

	iOrg = FlashSetBankOffset(MENU_BANK_OFFSET);
	MenuHandler(iEvent);
	FlashSetBank(iOrg);
#else
	iEvent;
#endif
}

void TaskCallLogAdd(PCHAR pName, PCHAR pNumber, UCHAR iType)
{
	UCHAR iOrg;

	iOrg = FlashSetBankOffset(MENU_BANK_OFFSET);
	CallLogAdd(pName, pNumber, iType);
	FlashSetBank(iOrg);
}

#ifdef SERIAL_UI
void TaskSerialSendString(PCHAR pStr)
{
	UCHAR iOrg;

	iOrg = FlashSetBankOffset(SERIAL_BANK_OFFSET);
	SerialSendString(pStr);
	FlashSetBank(iOrg);
}
#endif

typedef void (*DnsDone)(PCHAR pIP);

// The function calling TaskDnsQuery must be in the same bank as the call back function
void TaskDnsQuery(PCHAR pDomain, UCHAR iType, UCHAR iBankOffset, USHORT sCallBackAddr)
{
	UCHAR iOrg;
	// Can't do any preprocess here. It will cause loop call.
/*	UCHAR pDstIP[IP_ALEN];

	if (strlen(pDomain))
	{
		if (str2ip(pDomain, pDstIP))
		{	// domain name is a string of IP address
			TaskDnsDone(pDstIP, sCallBackAddr, iBankOffset);
		}
		else
		{
			iOrg = FlashSetBankOffset(NET_BANK_OFFSET);
			DnsQuery(pDomain, iType, iBankOffset, sCallBackAddr);
			FlashSetBank(iOrg);
		}
	}
	else
	{
		TaskDnsDone(NULL, sCallBackAddr, iBankOffset);
	}
*/

	iOrg = FlashSetBankOffset(NET_BANK_OFFSET);
	DnsQuery(pDomain, iType, iBankOffset, sCallBackAddr);
	FlashSetBank(iOrg);
}

void TaskDnsDone(PCHAR pIP, USHORT sAddr, UCHAR iBank)
{
	UCHAR iOrg;

	// remember to set page here before call call-back
	iOrg = FlashSetBankOffset(iBank);
	(*(DnsDone)sAddr)(pIP);
	FlashSetBank(iOrg);
}

typedef void (*TcpRunData)(TCP_HANDLE h, USHORT sLen, PCHAR pBuf);

void TaskRunTcp(TCP_HANDLE h, USHORT sLen, PCHAR pBuf, USHORT sAddr, UCHAR iBank)
{
	UCHAR iOrg;

	// remember to set page here before call call-back
	iOrg = FlashSetBankOffset(iBank);
	(*(TcpRunData)sAddr)(h, sLen, pBuf);
	FlashSetBank(iOrg);
}

void TaskTcpRun(PACKET_LIST * p)
{
	UCHAR iOrg;

	iOrg = FlashSetBankOffset(TCP_BANK_OFFSET);
	TcpRun(p);
	FlashSetBank(iOrg);
}

#endif

typedef void (*UdpRunData)(UDP_SOCKET pUcb);

void TaskUdpRunData(UDP_SOCKET pUcb)
{
	UCHAR iOrg;

	// remember to set page here before call call-back
	iOrg = FlashSetBankOffset(pUcb->iBankOffset);
	(*(UdpRunData)pUcb->sCallBack)(pUcb);
	FlashSetBank(iOrg);
}

void TaskIpSendData(USHORT sLen, PCHAR pDstIP, UCHAR iProtocol)
{
	UCHAR iOrg;

	iOrg = FlashSetBankOffset(NET_BANK_OFFSET);
	IpSendData(sLen, pDstIP, iProtocol);
	FlashSetBank(iOrg);
}

void TaskLoadString(UCHAR iIDS, PCHAR pBuf)
{
	UCHAR iOrg;

	iOrg = FlashSetBankOffset(MENU_BANK_OFFSET);
#ifdef CALL_NONE
	itoa(iIDS, pBuf, 10);
#else
	LoadString(iIDS, pBuf);
#endif
	FlashSetBank(iOrg);
}

void TaskUIHandler(UCHAR iType, USHORT sParam)
{
#ifdef CALL_NONE
	if (iType == UI_CHANGE_MODE)
	{
		Sys_iCurMode = (UCHAR)sParam;
	}
	else if (iType == UI_UPDATE_PROGRESS)
	{
		UI_UpdateProgress((UCHAR)sParam);
	}
#else
	UCHAR iOrg;

	iOrg = FlashSetBankOffset(UI_BANK_OFFSET);
	UI_EventHandler(iType, sParam);
	FlashSetBank(iOrg);
#endif
}

BOOLEAN TaskSystemHandler(UCHAR iType, UCHAR iParam)
{
	UCHAR iOrg;
	BOOLEAN bRet;

	iOrg = FlashSetBankOffset(UI_BANK_OFFSET);
	bRet = SystemHandler(iType, iParam);
	FlashSetBank(iOrg);

	return bRet;
}

void delay1ms() _naked
{
	_asm
	ld	b,	#0x04
contiune_delay213:
	// 11
	push	bc  
	// 7
	ld	b,	#0xf7
contiune_delay31:
	// 10 cycles
	ld	hl, #0x4567
	// 13 cycles
	djnz	contiune_delay31
	// 10
	pop		bc
	// change mips delay, 13
	djnz	contiune_delay213
	ret 
	_endasm;
}

#ifdef OEM_IP20

void sampleExec()
{
	UCHAR iOrg;
			
	iOrg = FlashSetBankOffset(UI_BANK_OFFSET);
	OnWake();
	//LcdDisplay("alarm2",2);
	FlashSetBank(iOrg);
}

UCHAR displayOnlineMissed(PCHAR ptr)
{
	UCHAR iOrg;	
	CALL_RECORD * p;
	UCHAR retval = 0;
	PCHAR ptr2;

	iOrg = FlashSetBankOffset(MENU_BANK_OFFSET);
	p = CallLogRead(0, 0);	
		
	if (p)
	{
		ptr2 = &p->iMem;
		strcpy(ptr, (PCHAR)(ptr2 + 1 + strlen(ptr2)));
		strcat(ptr, " <");
		strcat(ptr, ptr2);
		strcat(ptr, ">");
		retval = 1;		
	}
	FlashSetBank(iOrg);
	return retval;
}
#endif


