#include "p_apps.h"
#include "PalmChip.h"
#include "v_task.h"
#include "p_tcpip.h"
#include "ac97.h"

XCHAR Task_iTimer = 0;

XCHAR Key_pBuf[MAX_KEYBUF_LEN+1];
DCHAR Key_iCurrentID;
BOOLEAN PIO_bHandsetUp, PIO_bHandFree;
BOOLEAN PIO_bIndicated;				// Can be BOOLEAN
BOOLEAN KeyIO_bIndicated;			// Can be BOOLEAN
XCHAR PIO_iHookFlashTimer;
volatile DCHAR Slic_iDtmfKey;
volatile BOOLEAN Slic_bDtmfFlag = FALSE;

static volatile BOOLEAN _bKeypadIndicated;
static volatile BOOLEAN _bPIOIndicated;
static volatile BOOLEAN _bHandsetChanged;

BOOLEAN _GetHandsetStatus()
{
	BOOLEAN bUp;
       
	XBYTE[IO_LO_ENABLE] &= HANDSET_AND_MASK;
	if ((XBYTE[IO_LO_DIN] & HANDSET_OR_MASK))
	{
#ifdef _HANDSET_INVERT
		bUp = TRUE;
#else
		bUp = FALSE;
#endif
		XBYTE[IO_LO_INVERT] |= HANDSET_OR_MASK;	// Set irq to negative edge
	}
	else
	{
#ifdef _HANDSET_INVERT
		bUp = FALSE;
#else
		bUp = TRUE;
#endif
		XBYTE[IO_LO_INVERT] &= HANDSET_AND_MASK;	// Set irq to positive edge
	}
	return bUp;
}

void KeypadClear()
{
	Key_pBuf[0] = 0;
}

void KeypadBackspace()
{
	DCHAR iLen;

	iLen = p_strlen_x(Key_pBuf);
	if (iLen)
	{
		iLen --;
		Key_pBuf[iLen] = 0;
	}
}

void KeypadStartup()
{
	KeypadClear();

	_bKeypadIndicated = FALSE;
	_bPIOIndicated = FALSE;
	_bHandsetChanged = FALSE;

	// Check Handset
    XBYTE[IO_LO_INTEN] |= HANDSET_OR_MASK;			
//	XBYTE[IO_LO_EDGE] |= HANDSET_OR_MASK;
#ifdef _USE_FXS_AM79R70
	XBYTE[IO_LO_ENABLE] |= SLIC_CTRL_OR_MASK;
	XBYTE[IO_LO_DOUT] &= 0xfe;	// PIO0 = 0
	XBYTE[IO_LO_DOUT] |= 0x02;	// PIO1 = 1
	XBYTE[IO_LO_DOUT] &= 0xfb;	// PIO2 = 0

//	XBYTE[KEY_ENABLE] &= DTMF_CODE_AND_MASK;			// drive 4-bit of keyboard 
//	XBYTE[KEY_INTEN] = DTMFDET_OR_MASK;				// enable dtmf detect interrupt
//	XBYTE[KEY_EDGE] = DTMFDET_OR_MASK;				// enable edge detect keys 
#endif

	PIO_bHandsetUp = _GetHandsetStatus();
	PIO_bHandFree = FALSE;
	PIO_iHookFlashTimer = 0;
}

void KeypadHandleInterrupt()
{
	DCHAR iRow;

	// When enter interrupt, KEY_ENABLE should be 0x78, so that we could read the correc row value
	iRow = XBYTE[KEY_DIN] & KEYPAD_ROW;				// read row 
	XBYTE[KEY_INTCLR] = 0x7f;	// Clear keypad irq

	if (iRow)
	{
		_bKeypadIndicated = TRUE;
		XBYTE[INT_ENABLE] &= (~INT_MASK_KEY);	// disable keypad interrupt until it is handled
	}
}

UCHAR KeypadRead()
{
	DCHAR iVal, iKeyID;
	BOOLEAN bL3Clock;

	iVal = XBYTE[KEY_DIN] & KEYPAD_ROW;				// read row 
	XBYTE[KEY_ENABLE] = KEYPAD_ROW;					// switch to read column 
	iVal += XBYTE[KEY_DIN] & KEYPAD_COLUMN;		// read column 

	XBYTE[UDA_L3CLK] = 0;	// bit1 is 0 means input mode;
	bL3Clock = (XBYTE[UDA_L3CLK] & 0x04) ? TRUE : FALSE;

	// Set KEY_ENABLE to 0x78 again, so that next time we can get right value
	XBYTE[KEY_ENABLE] = KEYPAD_COLUMN;	// drive 4-bit of keyboard 
	switch (iVal)
	{
	case KEYPAD_0:
		iKeyID = '0';
		break;
	case KEYPAD_1:
		iKeyID = '1';
		break;
	case KEYPAD_2:
		iKeyID = '2';
		break;
	case KEYPAD_3:
		iKeyID = '3';
		break;
	case KEYPAD_4:
		iKeyID = '4';
		break;
	case KEYPAD_5:
		iKeyID = '5';
		break;
	case KEYPAD_6:
		iKeyID = '6';
		break;
	case KEYPAD_7:
		iKeyID = '7';
		break;
	case KEYPAD_8:
		iKeyID = '8';
		break;
	case KEYPAD_9:
		iKeyID = '9';
		break;
	case KEYPAD_STAR:
		iKeyID = '*';
		break;
	case KEYPAD_WELL:
		iKeyID = '#';
		break;
	// Below is the code for 6*7 Keypad, the added keyID in 6*7 keypad is from 'a'-'n'
	case 0x79:		// 0 1111 001	KEY0 pressed, if L3Clock=0, means L3Clock is pressed, else L3Mode is pressed
		iKeyID = bL3Clock ? 'n' : 'g';
		break;
	case 0x7a:		// 0 1111 010	KEY1 pressed, if L3Clock=0, means L3Clock is pressed, else L3Mode is pressed
		iKeyID = bL3Clock ? 'm' : 'f';
		break;
	case 0x7c:		// 0 1111 100	KEY2 pressed, if L3Clock=0, means L3Clock is pressed, else L3Mode is pressed
		iKeyID = bL3Clock ? 'l' : 'e';
		break;
	default:
		iKeyID = 0;
		break;
	}

	XBYTE[KEY_INTCLR] = 0x7f;	// Clear keypad irq
	XBYTE[INT_ENABLE] |= INT_MASK_KEY;	// enable keypad interrupt again
	_bKeypadIndicated = FALSE;
	return iKeyID;
}

void _HandleKeyJitters()
{
	SysSleep(20000);	// wait for 20ms
}

void _HandleKeys()
{
	if (!Key_iCurrentID)	return;
	if (IsUpgrading())		return;

	Task_iTimer = 0;
	if (Key_iCurrentID >= 'A' && Key_iCurrentID <= 'Z' || Key_iCurrentID >= 'a' && Key_iCurrentID <= 'n')
	{
		PIO_bIndicated = TRUE;
		HandleFunctionKeys();
	}
	else
	{
		KeyIO_bIndicated = TRUE;
		HandleNumberKeys();
	}
}

void _ClearAllInt()
{
	XBYTE[IO_LO_INTCLR] = 0xff;	// Clear all io edge irq
	XBYTE[IO_HI_INTCLR] = 0xff;	// Clear all io edge irq
	XBYTE[IO_HHI_INTCLR] = 0xff;	// Clear all io edge irq
}

/*
void _HandleHandset()
{
	DCHAR iVal;

	XBYTE[IO_LO_ENABLE] &= HANDSET_AND_MASK;
	iVal = XBYTE[IO_LO_DIN] & HANDSET_OR_MASK;
	if ((iVal == HANDSET_OR_MASK) || (!iVal))
	{
		XBYTE[IO_LO_INTCLR] |= HANDSET_OR_MASK;	// Clear io edge irq
		XBYTE[IO_LO_INTEN] &= HANDSET_AND_MASK;		// disable irq until key is processed
		_bHandsetChanged = TRUE;
	}
}
*/

void _HandleHandset()
{
	DCHAR iVal;

	XBYTE[IO_LO_ENABLE] &= HANDSET_AND_MASK;
	iVal = XBYTE[IO_LO_DIN]&HANDSET_OR_MASK;
	if (XBYTE[IO_LO_INVERT] & HANDSET_OR_MASK)
	{
		if (!iVal)
		{
			goto End;
		}
	}
	else
	{
		if (iVal)
		{
			goto End;
		}
	}
	return;

End:
	XBYTE[IO_LO_INTCLR] |= HANDSET_OR_MASK;	// Clear io edge irq
	XBYTE[IO_LO_INTEN] &= HANDSET_AND_MASK;		// disable irq until key is processed
	_bHandsetChanged = TRUE;
}

#ifdef VER_IPH_E00
void IoKeyHandleInterrupt()
{
	DCHAR iRow;
	BOOLEAN bHHI;

	_HandleHandset();

#ifdef _USE_FAKE_FXO
	HandleRingIn();
	HandleOffHook();
#endif
	// Check PIO 0, 1, 2
	XBYTE[IO_LO_ENABLE] &= 0xf8;
	iRow = XBYTE[IO_LO_DIN] & 0x07;
	XBYTE[IO_HHI_ENABLE] = 0;
	bHHI = XBYTE[IO_HHI_DIN] ? TRUE : FALSE;
	_ClearAllInt();
	if (iRow || bHHI)
	{
		_bPIOIndicated = TRUE;
		XBYTE[IO_LO_INTEN] &= 0xf8;			
	    XBYTE[IO_HHI_INTEN] = 0;			
	}
}

#else
void IoKeyHandleInterrupt()
{
#ifndef _USE_FXS
	DCHAR iRow;
	BOOLEAN bHHI;
#endif

	_HandleHandset();

#ifdef _USE_FAKE_FXO
//	if (!Line_b1S1OStatus)	// Phone connect to FXO port
	{
		HandleRingIn();
		HandleOffHook();
	}
#endif
	// Check PIO 0, 1, 2
#ifndef _USE_FXS
	XBYTE[IO_LO_ENABLE] &= 0xf8;
	iRow = XBYTE[IO_LO_DIN] & 0x07;
	XBYTE[IO_HHI_ENABLE] = 0;
	bHHI = XBYTE[IO_HHI_DIN] ? TRUE : FALSE;
#endif
	_ClearAllInt();
#ifndef _USE_FXS
	if (iRow || bHHI)
	{
		_bPIOIndicated = TRUE;
		XBYTE[IO_LO_INTEN] &= 0xf8;			
	    XBYTE[IO_HHI_INTEN] = 0;			
	}
#endif
}
#endif

UCHAR _IoKeyRead()
{
	DCHAR iVal, iIoKey;
	BOOLEAN bL3Clock;

	XBYTE[IO_LO_ENABLE] &= 0xf8;
	iVal = XBYTE[IO_LO_DIN] & 0x07;
#ifndef _USE_FXS
	XBYTE[IO_HHI_ENABLE] = 0;
	if (XBYTE[IO_HHI_DIN])
	{
		iVal += 0x80;
	}
#endif

#ifdef VER_IPH_E00
	XBYTE[IO_LO_ENABLE] &= 0xbf;					// turn off IOPAD4
#ifdef E00_NEW_HW
	XBYTE[IO_HI_ENABLE] &= 0xef;					// turn off IOPAD5
#else
	XBYTE[IO_HI_ENABLE] &= 0xdf;					// turn off IOPAD5
#endif // E00_NEW_HW
#endif
	XBYTE[KEY_ENABLE] = KEYPAD_ROW;					// switch to read column 

	XBYTE[IO_LO_ENABLE] |= 0x07;
	XBYTE[IO_HHI_ENABLE] = 1;
	iVal += XBYTE[KEY_DIN] & KEYPAD_COLUMN;			// read column

	XBYTE[UDA_L3CLK] = 0;	// bit1 is 0 means input mode;
	bL3Clock = (XBYTE[UDA_L3CLK] & 0x04) ? TRUE : FALSE;

#ifdef VER_IPH_E00
	if (!(XBYTE[IO_LO_DIN]&0x40))					// read IOPAD4 for Fun Key 1-3
	{
		iVal &= 0x07;
	}
#ifdef E00_NEW_HW
	else if (!(XBYTE[IO_HI_DIN]&0x10))				// read IOPAD5 for Soft Key 1-4
	{
		iVal |= 0xf8;
	}
#else
	else if (!(XBYTE[IO_HI_DIN]&0x20))				// read IOPAD5 for Soft Key 1-4
	{
		iVal |= 0xf8;
	}
#endif // E00_NEW_HW
#endif

	XBYTE[IO_LO_ENABLE] &= 0xf8;
#ifndef _USE_FXS
	XBYTE[IO_HHI_ENABLE] = 0;
#endif

	// Set KEY_ENABLE to 0x78 again, so that next time we can get right value
	XBYTE[KEY_ENABLE] = KEYPAD_COLUMN;	// drive 4-bit of keyboard 
#ifdef VER_IPH_E00
#ifdef E00_NEW_HW
	XBYTE[IO_HI_ENABLE] |= 0x10;					// turn on IOPAD5
#else
	XBYTE[IO_HI_ENABLE] |= 0x20;					// turn on IOPAD5
#endif // E00_NEW_HW
	XBYTE[IO_LO_ENABLE] |= 0x40;					// turn on IOPAD4
#endif

	switch (iVal)	//				DLINK_1			VOIP_DEV		PA168X			VIDA
	{
	case 0x3c:	// 0 0111 100		Info			up				redial			redial
		iIoKey = 'A';
		break;
	case 0x5c:	// 0 1011 100		Free call		call			record			record
		iIoKey = 'B';
		break;
	case 0x6c:	// 0 1101 100		Menu							local ip		local ip
		iIoKey = 'C';
		break;
	case 0x74:	// 0 1110 100		Set								(back space)	KEY1, (back_space)
		iIoKey = 'D';
		break;
	case 0x3a:	// 0 0111 010		Vol +			down			phone number	subnet mask
		iIoKey = 'E';
		break;
	case 0x5a:	// 0 1011 010		Vol -							service ip		router ip
		iIoKey = 'F';
		break;
	case 0x6a:	// 0 1101 010										router ip		service ip
		iIoKey = 'G';
		break;
	case 0x72:	// 0 1110 010		MEMORY DIAL						subnet mask		phone number
		iIoKey = 'H';
		break;
	case 0x39:	// 0 0111 001		SPEAKER			left			quick dial		quick dial
		iIoKey = 'I';
		break;
	case 0x59:	// 0 1011 001										memory			memory
		iIoKey = 'J';
		break;
	case 0x69:	// 0 1101 001		HOLD							delete			delete
		iIoKey = 'K';
		break;
	case 0x71:	// 0 1110 001		REDIAL							play			play
		iIoKey = 'L';
		break;
	case 0xb8:	// 1 0111 000						right			call			call
		iIoKey = 'M';
		break;
	case 0xd8:	// 1 1011 000										handfree		handfree
		iIoKey = 'N';
		break;
	case 0xe8:	// 1 1101 000						vol+			vol-			vol-
		iIoKey = 'O';     
		break;
	case 0xf0:	// 1 1110 000						vol-			vol+			vol+
		iIoKey = 'P';
		break;
	// Below is the code for 6*7 Keypad, the added keyID in 6*7 keypad is from 'a'-'n'
#ifndef VER_IPH_E00		// IPH_EOO will never use 6*7 keypad.
	case 0x79:		// 0 1111 001	PIO0 pressed, if L3Clock=0, means L3Clock is pressed, else L3Mode is pressed
		iIoKey = bL3Clock ? 'j' : 'c';
		break;
	case 0x7a:		// 0 1111 010	PIO1 pressed, if L3Clock=0, means L3Clock is pressed, else L3Mode is pressed
		iIoKey = bL3Clock ? 'i' : 'b';
		break;
	case 0x7c:		// 0 1111 100	PIO2 pressed, if L3Clock=0, means L3Clock is pressed, else L3Mode is pressed
		iIoKey = bL3Clock ? 'h' : 'a';
		break;
	case 0xf8:		// 1 1111 000	PIO16 pressed, if L3Clock=0, means L3Clock is pressed, else L3Mode is pressed
		iIoKey = bL3Clock ? 'k' : 'd';
		break;
#endif
//Diagnostic test		
#if defined VER_IPH_E00   //add function key selection
	case 0xf8:	// 1 1111 000						S1
		iIoKey = 'Q';
		break;
	case 0xf9:	// 1 1111 001						S2
		iIoKey = 'R';
		break;
	case 0xfa:	// 1 1111 010						S3
		iIoKey = 'S';
		break;
	case 0xfc:	// 1 1111 100						S4
		iIoKey = 'T';
		break;
	case 0x02:	// 0 0000 010						F1
		iIoKey = 'W';
		break;
	case 0x01:	// 0 0000 001						F2
		iIoKey = 'V';
		break;
	case 0x00:  // 0 0000 000						F3
		iIoKey = 'U';
		break;
#endif     //add key function end
	default:
		iIoKey = 0;
		break;
	}	

	_ClearAllInt();
    XBYTE[IO_LO_INTEN] |= 0x07;			
    XBYTE[IO_HHI_INTEN] = 1;			
	_bPIOIndicated = FALSE;
	return iIoKey;
}

void _HandsetRun()
{
	BOOLEAN bUp;

	_HandleKeyJitters();
	bUp = _GetHandsetStatus();
	if (PIO_bHandsetUp != bUp)
	{
		_ClearAllInt();
#ifdef _USE_FAKE_FXO
		if (!Line_b1S1OStatus)
		{
			goto End3;
		}
#endif
		PIO_bHandsetUp = bUp;
		if (bUp)
		{
			if (PIO_iHookFlashTimer < 20 && PIO_iHookFlashTimer > 1)
			{
				// it is hook flash event.
				Ac97WriteReg(AC97_MASTER_VOL_STEREO, AC97_RIGHTVOL_HI, AC97_SPK_VOL_MAX - Ac97_iHandsetOutputVol);
				PIO_iHookFlashTimer = 0;
				OnHookFlash();
			}
			else
			{
				OnHandset();
			}
		}
		else
		{
			Ac97WriteReg(AC97_MASTER_VOL_STEREO, AC97_MUTE_HI, AC97_MUTE_LO);		// set master volume
//			OutputVal(5, IDS_CHECK_POINT_7);
			PIO_iHookFlashTimer = 1;
		}
	}
#ifdef _USE_FAKE_FXO
End3:
#endif
	_bHandsetChanged = FALSE;
    XBYTE[IO_LO_INTEN] |= HANDSET_OR_MASK;			// enable irq
}

void KeypadRun()
{
#ifdef BACKLIGHT_CTRL
	if (_bKeypadIndicated || _bPIOIndicated) 
	{
//		L3ClockOn();
#ifdef INVERT_BACKLIGHT
		Cam_LedOn(0);
#else
		Cam_LedOff(0);
#endif
		Task_iTimer = 0;
	}
#endif

	if (_bKeypadIndicated)
	{
		_HandleKeyJitters();
		Key_iCurrentID = KeypadRead();
#ifdef _USE_FXS
		if (Key_iCurrentID == '*')
		{
			Key_iCurrentID = 'C';
		}
#endif
		_HandleKeys();
	}

	if (_bHandsetChanged)	
	{
		_HandsetRun();
	}

#ifdef _USE_FAKE_FXO
	DualModeRun();
#endif

	if (Slic_bDtmfFlag)
	{
		OutputVal(Slic_iDtmfKey, IDS_REMOTE_DTMF);

		Key_iCurrentID = p_getAsciiKey(Slic_iDtmfKey);
#ifdef _USE_FXS
		_HandleKeys();
#endif
		Slic_bDtmfFlag = FALSE;
	}

	if (_bPIOIndicated)
	{
		_HandleKeyJitters();
		Key_iCurrentID = _IoKeyRead();
		_HandleKeys();
	}
}
