#include <stdlib.h>
#include "al_console.h"
#include "al_console_customer.h"
#include "kmf_ioctl.h"
#include "ap_extern.h"
#include "drv_pq_external.h"
#include "nvm_ioctl.h"
#include "util_ioctl.h"
#include "al_fw.h"
#include "subcustomer_setting.h"
#include "umf_ir.h"
#include "MM_media_qsd_gui.h"
#include "drv_tuner_external.h"
#include <sys/time.h>
#include "mid_tvfe.h"
#include "drv_uart_def.h"
//#include "mid_upgrade.h"
#ifdef CONFIG_SUPPORT_DBX
#include "../../../../../../include/middleware/ptnmng/partitionlist/mid_partition_list.h"
#include "audio_ioctl.h"

static char g_PresetFile[50] = {0};
#endif

extern Ser8250_IOData UARTA_Wdata;
extern int uartafd;
extern void av_free(void *ptr);
con_CallBack_t ConCallBack = NULL;

volatile BOOL bWaitAck = FALSE;
UINT16 gUSBTestResult = AutoTest_usb_none;
UINT8 gUpdateResult = AutoTest_usb_none;
UINT8 bSkipCmd = FALSE;

UINT8 bReceiveIRTest = FALSE;

AutoTest_ACK_TYPE gSendAck;
extern UINT8 CMD_AutoTest_HEADER[3];
//extern UINT8 timerCount;
//extern USBMsg g_USBDeviceInfo;
//extern UINT8 bReceiveIRTest;

enum _UPDATE_STATE
{
	UPDATE_STATE_OK=0x0,
	BACKUP_STATE_OK,
	RESET_STATE_OK,
	RECOVE_STATE_OK,
	UPDATE_STATE_NO_USB_DEV,
	UPDATE_STATE_NO_FIT_FILE,	//sd or usb file not found, please insert SD/USB
	UPDATE_STATE_FILE_SIZE_ERROR,
	UPDATE_STATE_CRC_ERROR,
	UPDATE_STATE_SPI_ERROR,			//spi misc errors
	UPDATE_STATE_CHECK_SUM_ERROR,//20081209 Kai add
	UPDATE_STATE_PROJECT_ID_ERROR,
	UPDATE_STATE_SAVE_FILE_ERROR,
	UPDATE_STATE_DTV_FW_ERROR,//20090908 Ivan add
	UPDATE_STATE_BOOTROM_VER_ERROR, 	//bootrom version different with kernel
	UPDATE_STATE_TAR_NOTFOUND, 		//sis_android_fs.tar not found
	UPDATE_STATE_NAND_ERROR,		//nand flash broken
	UPDATE_STATE_NOR_FLASH_ERROR,		//nor flash progrma error
	RECOVE_STATE_NO_FIT_FILE,
	BACKUP_STATE_DEV_FAIL,			//disc fail when backup
	UPDATE_CONTINUE,
	UPDATE_STATE_NO_FREESPACE,	//sd or usb not have enough freespace to unzip
	UPDATE_STATE_ERROR=0xff,
};

static void con_send(void)
{
	ioctl(uartafd, SiS_UART_WRITE, &UARTA_Wdata);
	con_ShowHexValuetoOSD(RS_Rx, UARTA_Wdata.len, &UARTA_Wdata.buff[0]);
	con_SaveDbgMsgtoUSB(RS_Rx, UARTA_Wdata.len, &UARTA_Wdata.buff[0]);
}

void con_echo(pCON_DEV pcon, unsigned int parm)
{
	con_print(/*pcon,*/(char*)&parm,4);
}

void con_echo1(pCON_DEV pcon, UINT8 data1, UINT8 data2)
{
	UINT8 msg[2] = {0x00,0x00};

	msg[0] = data1;
	msg[1] = data2;
	UARTA_Wdata.len = 2;
	memcpy(UARTA_Wdata.buff, &msg[0], 2);
	con_send();
}

void con_echo_respond_message(UINT16 count, UINT8 *pdata)
{
	UARTA_Wdata.len = count;
	memcpy(UARTA_Wdata.buff, pdata, count);
	con_send();
}

void con_dbg_echo(unsigned char data1, unsigned char data2)
{
	con_echo1(get_pCON_DEV(), data1, data2);
}

void con_QSD_echo(pCON_DEV pcon, UINT8 success)
{
	INT8 msg_ok[4] = {'G', 'O', 'O', 'D'};
	INT8 msg_fail[4] = {'B', 'A', 'D', '!'};
	INT8 msg_done[4] = {'D', 'O', 'N', 'E'};

	if(success == QSD_success)
	{
		con_print(/*pcon,*/ msg_ok, 4);
	}
	else if(success == QSD_done)
	{
		con_print(/*pcon,*/ msg_done, 4);
	}
	else
	{
		con_print(/*pcon,*/ msg_fail, 4);
	}

}

static void PQ_Read_Table_Info(pCON_DEV pcon, UINT8 Value)
{
	UINT8 ModuleID[4] = {FLASH_ID_VIPTABLE, FLASH_ID_GAMMATABLE, FLASH_ID_PANELSET, FLASH_ID_CLUPTABLE};
	UINT32 pSize = 0, pfalshAddr = 0;
	UINT8 Index = 0;

	Index = ModuleID[Value];
	Cmd_GetAddrAndSizeByFlashID(Index, &pfalshAddr, &pSize); // to get PQ Table size info

	con_print(/*pcon,*/ (char*)&pfalshAddr, 4);
	con_print(/*pcon,*/ (char*)&pSize, 4);
}

void con_RegCallBackFunc(con_CallBack_t pCallBackFunc)
{
	ConCallBack = pCallBackFunc;
}

bool con_SIS_parser(pCON_DEV pcon, UINT8 *msg)
{
	UINT8 lenH  = *(msg+0);
	UINT8 lenL  = *(msg+1);
	UINT8 cmd   = *(msg+2);
	UINT8 data1 = *(msg+3);
	UINT32 val = 0;
	UINT32 size = 0;
	//PQ_SW_DYNAMICCONTRAST_INFO DynamicContrastInfo;
	//UINT8 *pDynamicContrastInfo;
	UINT8 *pCmdSet = NULL; // for PQ Cmd Set
	UINT32 nCmdSetSize; // for PQ Cmd Set
	UINT32 addr;
	UINT8 buffer[5120];

	switch(cmd)
	{
		case CMD_PQ_Leave:
			con_echo1(pcon, 0xFF, 0x01);
			return FALSE;

		case CMD_PQ_Echo:
			con_echo1(pcon, 0xFF, 0x01);
			break;

		case CMD_PQ_Read_Table_Info:
			PQ_Read_Table_Info(pcon, data1);
			break;

		case CMD_PQ_Cmd_Set:
		// ---------------- PQ command set foramt  ------------------------------
		// len     1       2     3      4       5        6	7     8       9    ........  9+n        10+n
		// Data 0xFA lenH lenL 0x15 Cmd1 Cmd2  Rev Rev  data1 .......  datan    checksum
		//--------------------------------------------------------------------
		{
			KMFIOCTL_t kmfioctl;
			nCmdSetSize = *(UINT32*)(msg+3);
			size = lenH * 256 + lenL;
			pCmdSet =(UINT8 *)malloc(nCmdSetSize);
			if(pCmdSet == NULL)
			{
				con_echo1(pcon, 0xFF, 0xA0);
			}
			else
			{
				memcpy(pCmdSet, msg+3, size-5);
				kmfioctl.bufSize = nCmdSetSize;
				kmfioctl.pBuf = (void*)pCmdSet;
				val = ioctl(kmfdev, KMF_IOC_SETPQCMDSET, &kmfioctl);
				if (val)
				{
					con_echo1(pcon, 0xFF, 0xA1);
				}
				else
				{
					con_echo1(pcon, 0xFF, 0x01);
					nCmdSetSize = *(UINT32*)pCmdSet; //if Set function, nCmdSetSize should be set 0, else if Get function, nCmdSetSize should be GotDataSize
					if(nCmdSetSize > 0)
					{
						con_print(/*pcon,*/ (char*)pCmdSet+8, nCmdSetSize);
					}
				}
			}
			free(pCmdSet);
			break;
		}

		case CMD_PQ_Read_DynXastInfo:
			//pDynamicContrastInfo=(UINT8 *)malloc(sizeof (PQ_SW_DYNAMICCONTRAST_INFO));
			//ioctl(kmfdev, KMF_IOC_VIP_GetDynamicContrastInfo, &DynamicContrastInfo);
			//memcpy(pDynamicContrastInfo, &DynamicContrastInfo, sizeof (PQ_SW_DYNAMICCONTRAST_INFO));
			//con_echo1(pcon, 0xFF, 0x01);
			//con_print(pcon, pDynamicContrastInfo, sizeof (PQ_SW_DYNAMICCONTRAST_INFO));
			//free(pDynamicContrastInfo);
			break;

		case CMD_PQ_Write_DynXastInfo:
			//memset(&DynamicContrastInfo.HistMinSlope[0], 0x0, sizeof (PQ_SW_DYNAMICCONTRAST_INFO));
			//memcpy(&DynamicContrastInfo.HistMinSlope[0], msg+3, sizeof (PQ_SW_DYNAMICCONTRAST_INFO));
			//ioctl(kmfdev, KMF_IOC_VIP_SetDynamicContrastInfo, &DynamicContrastInfo);
			//con_echo1(pcon, 0xFF, 0x01);
			break;

		case CMD_PQ_MMIO_Read:
			addr = (UINT32)((*(msg+3) << 24) + (*(msg+4) << 16) + (*(msg+5) << 8) + *(msg+6));
			Cmd_mmio_ReadUINT32(addr, &val);
			con_echo(pcon, val);
			break;

		case CMD_PQ_MMIO_Write:
			addr = (UINT32)((*(msg+3) << 24) + (*(msg+4) << 16) + (*(msg+5) << 8) + *(msg+6));
			val  = (*(msg+7) << 24) + (*(msg+8) << 16) + (*(msg+9) << 8) + *(msg+10);
			Cmd_mmio_WriteUINT32(addr, val);
			con_echo1(pcon, 0xFF, 0x01);
			break;

		/*case CMD_PQ_Reboot:
			//mmio_writeDWmask(0xbe000054,0x80,0x80);
			tv_SetRebootAfterPowerOff();
			tv_Shutdown();
			con_echo1(pcon, 0xFF, 0x01);
			break;*/

		case CMD_PQ_Read_Flash:
			addr = (UINT32)((*(msg+3) << 24) + (*(msg+4) << 16) + (*(msg+5) << 8) + *(msg+6));
			size = (*(msg+7) << 8)+ *(msg+8);
			Cmd_MEMRead(addr, (UINT32)buffer, size);
			con_print(/*pcon,*/ (char*)buffer, size);
			break;
		/*
		case CMD_PQ_Write_Flash:
			(UINT32*)addr = (UINT32*)(void*)((data1 << 24) + (data2 << 16) + (data3 << 8) + data4);
			size = (data5 << 8)+ data6;
			val = tv_write_flash(addr, msg+7, size);
			(val)?con_echo1(pcon, 0xFF, 0x00):con_echo1(pcon, 0xFF, 0x01);
			break;



		case CMD_PQ_Set_GammaTab:
			val = tv_SetVIPGammaTable((UINT32*)(msg+1));
			if(val)
				con_echo1(pcon, 0xFF, 0x00);
			else
				con_echo1(pcon, 0xFF, 0x01);
			break;


*/
		case CMD_PQ_Set_GammaTab:
			val = tv_SetVIPGammaTable((unsigned long*)(msg+3));
			if(val)
				con_echo1(pcon, 0xFF, 0x00);
			else
				con_echo1(pcon, 0xFF, 0x01);
			break;

		case CMD_System_Call:
			con_echo1(pcon, 0xFF, 0x01);
			system((char*)msg+3);
			break;

		default:
			con_echo1(pcon, 0xFF, 0x02);
			break;
	}

	return TRUE;
}

static Console_sfu_Cbk_pf g_pfpConsole_SfuCallback = NULL;

void con_echo_sfu(UINT32 count, UINT8 *pdata)
{
	UARTA_Wdata.len = count;
	memcpy(UARTA_Wdata.buff, pdata, count);
	con_send();
}

void con_echo_sfu_Save2Usb(UINT32 count, UINT8 *pdata)
{
    con_SetDbgMsgtoUSB(1);
	UARTA_Wdata.len = count;
	memcpy(UARTA_Wdata.buff, pdata, count);
	con_SaveDbgMsgtoUSB(RS_Rx, UARTA_Wdata.len, &UARTA_Wdata.buff[0]);
    con_SetDbgMsgtoUSB(0);
}

void con_echo_sfu_tx_Save2Usb(UINT32 count, UINT8 *pdata)
{
    con_SetDbgMsgtoUSB(1);
	UARTA_Wdata.len = count;
	memcpy(UARTA_Wdata.buff, pdata, count);
	con_SaveDbgMsgtoUSB(RS_Tx, UARTA_Wdata.len, &UARTA_Wdata.buff[0]);
    con_SetDbgMsgtoUSB(0);
}


bool con_suf_parser(pCON_DEV pcon, UINT8 *msg)
{
	bool ret = TRUE;

	if(g_pfpConsole_SfuCallback != NULL)
	{
	   ret = g_pfpConsole_SfuCallback(pcon,(UINT8*)(msg));
	}
	else
	{
	   return FALSE;
	}

	return ret;
}

void al_console_sfu_init(Console_sfu_Cbk_t *pConsole_Sfu_Cfg)
{
	if ((pConsole_Sfu_Cfg != NULL) && (pConsole_Sfu_Cfg->pfCallBack != NULL))
	{
		g_pfpConsole_SfuCallback = pConsole_Sfu_Cfg->pfCallBack;
	}
}

static Console_ats_Cbk_pf g_pfpConsole_AtsCallback = NULL;
int con_ats_parser(pCON_DEV pcon, UINT8 *msg)
{
	int ret = FALSE;

	if(g_pfpConsole_AtsCallback != NULL)
	{
	   ret = g_pfpConsole_AtsCallback(pcon,(UINT8*)(msg));
	}
	else
	{
	   return FALSE;
	}

	return ret;
}

void al_console_ats_init(Console_ats_Cbk_t *pConsole_Sfu_Cfg)
{
	if ((pConsole_Sfu_Cfg != NULL) && (pConsole_Sfu_Cfg->pfCallBack != NULL))
	{
		g_pfpConsole_AtsCallback = pConsole_Sfu_Cfg->pfCallBack;
	}
}

static Console_autotest_Cbk_pf g_pfpConsole_AutoTestCallback = NULL;

void con_autotest_HeaderParse(unsigned char* buff, unsigned int bufflen, unsigned int *commandlen)
{
    if (bufflen < 2 || ((buff[0] != CMD_AUTOTEST_SYNC_AA) && (buff[0] != CMD_AUTOTEST_SYNC_AB)) || commandlen == NULL)
    {
        return ;
    }

    *commandlen = *(buff + 1);

    if (*commandlen == 0xfe)
    {
        if (bufflen < 4)
        {
            *commandlen = 0;
        }
        else
        {
            *commandlen = ((buff[2]<<8)|buff[3]);
        }
    }
}

bool con_autotest_parser(pCON_DEV pcon, UINT8 *msg)
{
	bool ret = TRUE;

	if(g_pfpConsole_AutoTestCallback != NULL)
	{
	   ret = g_pfpConsole_AutoTestCallback(pcon,(UINT8*)(msg));
	}
	else
	{
	   return FALSE;
	}

	return ret;
}
void al_console_autotest_init(Console_autotest_Cbk_t *pConsole_autotest_Cfg)
{
	if ((pConsole_autotest_Cfg != NULL) && (pConsole_autotest_Cfg->pfCallBack != NULL))
	{
		g_pfpConsole_AutoTestCallback = pConsole_autotest_Cfg->pfCallBack;
	}
}

#ifdef CONFIG_QSD
UINT8 bWaitRet = 0;
UINT8 mmiotest_result = 0;
#endif
void con_mmiotest_status(UINT8 status)
{
	printf(" mmiotest_result:%d \n", status);
#ifdef CONFIG_QSD
	bWaitRet = 0;
	mmiotest_result = status;
#endif
}

#ifdef CONFIG_QSD
bool con_src_parser(pCON_DEV pcon,unsigned char *msg)
{
	UINT8 data1	= *(msg+0);
	UINT8 data2	= *(msg+1);
	UINT8 data3	= *(msg+2);
	UINT8 data4	= *(msg+3);
	UINT8 data5	= *(msg+4);
	UINT8 data6	= *(msg+5);
	UINT8 data7	= *(msg+6);
	UINT8 data8	= *(msg+7);
	UINT8 data9	= *(msg+8);
	UINT32 srcId = 0;
	APP_Source_Type_t eSourceType = APP_SOURCE_MAX;
	frmwrk_pfOpConext_t pfQSDGetContext = al_null;
	AL_FW_GetContextCb(&pfQSDGetContext);

	switch(data1)
	{
		case 'a': // src atv xx-xx
			if(data2 == 't' && data3 == 'v')
			{
				AL_FW_ActiveFWModule(FW_QSD_MODE);
				srcId = APP_SOURCE_ATV;
				pfQSDGetContext(FW_CONTEXT_TYPE_GET_Current_Source , FW_CONTEXT_OP_TYPE_READ,(al_void *)&eSourceType, 0);
				if(eSourceType != srcId)
				{
					ConCallBack(FW_QSD_Source_Set, srcId, 0);
				}
				if(data4 == ' ' && data5 >= '0' && data5 <= '9' && data6 >= '0' && data6 <= '9')
				{
					if(ConCallBack != NULL)
					{
						ConCallBack(FW_QSD_ATV_SetCH, (data5-0x30)*10+(data6-0x30), 0);
					}
					con_QSD_echo(pcon, QSD_success);
				}
				else
				{
					con_QSD_echo(pcon, QSD_fail);
				}
				return TRUE;
			}
			break;

		case 'd': // src dtv xx-xx
			if(data2 == 't' && data3 == 'v')
			{
				AL_FW_ActiveFWModule(FW_QSD_MODE);
				srcId = APP_SOURCE_DTV;
				pfQSDGetContext(FW_CONTEXT_TYPE_GET_Current_Source , FW_CONTEXT_OP_TYPE_READ,(al_void *)&eSourceType, 0);
				if(eSourceType != srcId)
				{
					ConCallBack(FW_QSD_Source_Set, srcId, 0);
				}
				if(eSourceType != APP_SOURCE_DTV)
				{
					//APP_GUIOBJ_Source_SetAppSource(srcId);
				}

				if(data4 == ' ' && data5 >= '0' && data5 <= '9' && data6 >= '0' && data6 <= '9' && data7 == '-' && data8 >= '0' && data8 <= '9'
					&& data9 >= '0' && data9 <= '9')
				{
					if(ConCallBack != NULL)
					{
						ConCallBack(FW_QSD_DTV_SetCH, (data5-0x30)*10+(data6-0x30), 0);
					}
					con_QSD_echo(pcon, QSD_success);
				}
				else
				{
					con_QSD_echo(pcon, QSD_fail);
				}
				return TRUE;
			}
			break;

		case 's': // src s1
			if(data2 == '1')
				srcId = APP_SOURCE_SVIDEO;
			else
				srcId = 0xffff;
			break;

		case 'c': // src cvbs
				  // src com1
				  // src com2
			if(data2 == 'v' && data3 == 'b' && data4 == 's')
				srcId = APP_SOURCE_AV;
			else if(data2 == 'o' && data3 == 'm' && data4 == '1')
				srcId = APP_SOURCE_YPBPR;
			else if(data2 == 'o' && data3 == 'm' && data4 == '2')
				srcId = APP_SOURCE_YPBPR1;
			else
				srcId = 0xffff;
			break;

		case 'h': // src hdmi 1 ...... src hdmi 3
			if(data2 == 'd' && data3 == 'm' && data4 == 'i')
			{
				if(data5 == '1')
					srcId = APP_SOURCE_HDMI;
				else if(data5 == '2')
					srcId = APP_SOURCE_HDMI1;
				else if(data5 == '3')
					srcId = APP_SOURCE_HDMI2;
				else
					srcId = 0xffff;
			}
			else
			{
				srcId = 0xffff;
			}
			break;

		case 'p': // src pc
			if(data2 == 'c')
				srcId = APP_SOURCE_PC;
			else
				srcId = 0xffff;
			break;

		case 'j': // src jpegx
		case 'm': // src mpegx
			if(data2 == 'p' && data3 == 'e' && data4 == 'g')
			{
				if(data1 == 'j')
					ConCallBack(FW_QSD_Media_Play, MEDIA_JPEG, 0);
				else
					ConCallBack(FW_QSD_Media_Play, MEDIA_MPEG, 0);
				con_QSD_echo(pcon, QSD_success);
				return TRUE;
			}
			else
			{
				srcId = 0xffff;
			}
			break;

		default:
			srcId = 0xffff;
			break;
	}

	if(srcId == 0xffff)
	{
		con_QSD_echo(pcon, QSD_fail);
	}
	else
	{
		pfQSDGetContext(FW_CONTEXT_TYPE_GET_Current_Source , FW_CONTEXT_OP_TYPE_READ,(al_void *)&eSourceType, 0);
		if(eSourceType != srcId)
		{
			ConCallBack(FW_QSD_Source_Set, srcId, 0);
		}
		con_QSD_echo(pcon, QSD_success);
	}

	return TRUE;
}


struct timeval StdTime;

void con_GetDiffTime(pCON_DEV pcon, INT8 tag)
{
	INT16 Difftime = 0;
	struct timeval CurrTime;
	gettimeofday(&CurrTime, NULL);
	Difftime = CurrTime.tv_sec - StdTime.tv_sec;
	con_echo1(pcon, tag, (Difftime >> 8));
	con_echo1(pcon, tag+1, (Difftime & 0xFF));
}

#define mmoitestFull 0
UINT8 con_mmiotest(pCON_DEV pcon)
{
	INT8 cmd[64] = {0}, i = 0;
	UINT8 ret = 0;
	UINT16 counter = 0;
	FrontendCmd_t  front;
	char *usbpath, *testfile = "out_gram", maxtest = 0;

#if mmoitestFull
	maxtest = 33;
#else
	maxtest = 3;
#endif

	gettimeofday(&StdTime, NULL);
	usbpath = MM_MediaQsd_FindMMIOTestPath();


	front.cmd = FRONTEND_CMD_SET_T2;
	front.param = NULL;
	ioctl(kmfdev, KMF_IOC_FRONTENDCTRL , &front);

	//wehn mmiotest start, TV set to blue screen
	MID_DISP_DTVSetMTMute(0, 0, 255);
	system("chmod 777 /tmp/mmiotest");
	for(i=0 ; i<maxtest; i++)
	{
		front.cmd = FRONTEND_CMD_RESET_DVBT2_FOR_MT;
		front.param = NULL;
		ioctl(kmfdev, KMF_IOC_FRONTENDCTRL , &front);
		memset(cmd, 0x0, 64);

		if(maxtest == 33)
		{
			if(i == 31)
			{
				con_GetDiffTime(pcon, 0xA1);
				sprintf(cmd, "/tmp/mmiotest %s/out_allRam.txt", usbpath);
			}
			else if(i == 32)
			{
				con_GetDiffTime(pcon, 0xA3);
				sprintf(cmd, "/tmp/mmiotest %s/ldpc_dvbt2.txt", usbpath);
			}
			else
			{
				sprintf(cmd, "/tmp/mmiotest %s/%s%d.txt", usbpath, testfile, i);
			}
		}
		else
		{
			if(i == 0)
			{
				sprintf(cmd, "/tmp/mmiotest %s/mcp_memory_full_gram_easy.txt", usbpath);
			}
			else if(i == 1)
			{
				con_GetDiffTime(pcon, 0xA1);
				sprintf(cmd, "/tmp/mmiotest %s/out_allRam.txt", usbpath);
			}
			else if(i == 2)
			{
				con_GetDiffTime(pcon, 0xA3);
				sprintf(cmd, "/tmp/mmiotest %s/ldpc_dvbt2.txt", usbpath);
			}
		}

		bWaitRet = 1;
		system(cmd);
		while(bWaitRet)
		{
			if(counter > 2000)
			{
				mmiotest_result = 2;
				bWaitRet = 0;
			}
			umfsleep(0,10000000);
			counter++;
		}
		con_echo1(pcon, i, mmiotest_result);
		counter = 0;
		if(mmiotest_result != 1)
		{ //wehn mmiotest fail, TV set to red screen
			MID_DISP_DTVSetMTMuteColor(255, 0, 0);
			ret = 0xFF;
			break;
		}
	}
	if(ret != 0xFF)
	{
		con_GetDiffTime(pcon, 0xA5);
		//wehn mmiotest success, TV set to green screen
		MID_DISP_DTVSetMTMuteColor(0, 255, 0);
	}

	return ret;
}


bool con_new_src_parser(pCON_DEV pcon,unsigned char *msg)
{
	UINT8 data1	= *(msg+0);
	UINT8 data2	= *(msg+1);
	UINT8 data3	= *(msg+2);
	UINT8 data4	= *(msg+3);
	UINT8 data5	= *(msg+4);
	UINT8 data6	= *(msg+5);
	UINT32 srcId = 0;
	APP_Source_Type_t eSourceType = APP_SOURCE_MAX;
	frmwrk_pfOpConext_t pfQSDGetContext = al_null;
	AL_FW_GetContextCb(&pfQSDGetContext);

	switch(data1)
	{
		case 'a': //  atv
			if(data2 == 't' && data3 == 'v')
			{
				srcId = APP_SOURCE_ATV;
			}
			else if(data2 == 'v' && data3 == '1')
			{
				srcId = APP_SOURCE_AV;
			}
			else
			{
				srcId = 0xffff;
			}
			break;

		case 'd': // dtv
		case 'f': // dtv and set frequency
			if(data2 == 't' && data3 == 'v')
			{
				srcId = APP_SOURCE_DTV;
			}
			else if(data2 == 'r' && data3 == 'e' && data4 == 'q')
			{
				srcId = APP_SOURCE_DTV;
				ConCallBack(FW_QSD_DTV_SetFreq, 0, 0); // when set source to DTV, it needs to display video in special frequency without scanning channel.
			}
			else
			{
				srcId = 0xffff;
			}
			break;
		case 'm':
			if(data2 == 'm' && data3 == 'i' && data4 == 'o')
			{
				con_QSD_echo(pcon, QSD_success);
				if(con_mmiotest(pcon) == 0xFF)
				{
					srcId = 0xffff;
				}
				else
				{
					srcId = 0xff01;
				}
			}
			else if(data2 == 'p' && data3 == 'e' && data4 == 'g') //mdeia mpeg
			{
				ConCallBack(FW_QSD_Media_Play, MEDIA_MPEG, 0);
				con_QSD_echo(pcon, QSD_success);
				return TRUE;
			}
			else
			{
				srcId = 0xffff;
			}
			break;

		case 's': //  svideo
			if(data2 == 'v' && data3 == 'i' && data4 == 'd' && data5 == 'e' && data6 == 'o')
			{
				srcId = APP_SOURCE_SVIDEO;
			}
			else if(data2 == 'c' && data3 == 'a' && data4 == 'r' && data5 == 't')
				srcId = APP_SOURCE_SCART;
			else
			{
				con_echo1(pcon, 0xAA, 0xA1);
				con_echo1(pcon, data1, data2);
				con_echo1(pcon, data3, data4);
				con_echo1(pcon, data5, data6);
				srcId = 0xffff;
			}
			break;

		case 'h':
			if(data2 == 'd' && data3 == 'm' && data4 == 'i' && data5 == '1') //  hdmi 1
			{
				srcId = APP_SOURCE_HDMI;
			}
			else if(data2 == 'd' && data3 == 'm' && data4 == 'i' && data5 == '2') //  hdmi 2
			{
				if (CONFIG_HDMI_NUM>=3)
					srcId = APP_SOURCE_HDMI2;
				else
					srcId = APP_SOURCE_HDMI1;
			}
			else
			{
				srcId = 0xffff;
			}
			break;

		case 'y':
			MID_DISP_DTVSetMTUnmute();
			if(data2 == 'p' && data3 == 'b' && data4 == 'p' && data5 == 'r') // comp
			{
				srcId =APP_SOURCE_YPBPR;
			}
			else
				srcId = 0xffff;
			break;
		case 'p': // src pc
			if(data2 == 'c')
				srcId = APP_SOURCE_PC;
			else
				srcId = 0xffff;
			break;
		case 'j': // mdeia jpeg
			if(data2 == 'p' && data3 == 'e' && data4 == 'g')
			{
				ConCallBack(FW_QSD_Media_Play, MEDIA_JPEG, 0);
				con_QSD_echo(pcon, QSD_success);
				return TRUE;
			}
			else
			{
				srcId = 0xffff;
			}
			break;		
		case 'n': //net loopback
			if(data2 == 'e' && data3 == 't' && data4 == 'l' && data5 == 'b' )
			{
				system("lb 3 1"); // test 3 s
				return TRUE;
			}
			else
			{
				srcId = 0xffff;
			}
			break;
		
		default:
			srcId = 0xffff;
			break;
	}

	if(srcId == 0xffff)
	{
		con_QSD_echo(pcon, QSD_fail);
	}
	else if(srcId == 0xff01)
	{
		con_QSD_echo(pcon, QSD_done);
	}
	else
	{
		pfQSDGetContext(FW_CONTEXT_TYPE_GET_Current_Source , FW_CONTEXT_OP_TYPE_READ,(al_void *)&eSourceType, 0);
		if(eSourceType != srcId)
		{
			ConCallBack(FW_QSD_Source_Set, srcId, 0);
			if(srcId == APP_SOURCE_DTV)
			{
				while(eSourceType != APP_SOURCE_DTV) // Wait the flow which set source to DTV is finished.
				{
					pfQSDGetContext(FW_CONTEXT_TYPE_GET_Current_Source , FW_CONTEXT_OP_TYPE_READ,(al_void *)&eSourceType, 0);
					umfsleep(0, 10000000);
				}
			}
		}
		else
		{
			con_QSD_echo(pcon, QSD_success);
		}
	}

	return TRUE;
}
#endif

#if defined(SUPPORT_FACTORY_AUTO_TEST_MODE4)
void AutoTest_cmd_send(UINT8 * str, int size)
{
    int count = 0, outsize = 0;
    UINT32 len = 0;
    INT8 buff[UART_BUF_SIZE] = { 0 };

    outsize = size;

		if(uartafd<=0)
			printf("Consloe closed.\n");
    while (1)
    {
        len = (outsize >= UART_BUF_SIZE) ? UART_BUF_SIZE : outsize;
        memcpy(buff, (str + count * UART_BUF_SIZE), len);
        con_print(buff, len);

        if (outsize > UART_BUF_SIZE)
        {
            count++;
            outsize -= UART_BUF_SIZE;
        }
        else
        {
            break;
        }
    }
}

unsigned int AutoTest_crc_check(unsigned char *fp_CRC,int count)
{
 unsigned int CRC=0xFFFF;
 unsigned char CRC_count;

 if(count<=0)
  return count;


 for(CRC_count=0;CRC_count<count;CRC_count++)
 {
  int i;

  CRC=CRC^*(fp_CRC+CRC_count);
  for(i=0;i<8;i++)
  {
   if(CRC&1)
   {
    CRC>>=1;
    CRC^=0XA001;
   }
    else CRC>>=1;
   }
 }

return CRC;

}

UINT32 AutoTest_TransTVSource(UINT8 cmdSrc, UINT32 srcID)
{/*
	if(srcID)
	{
		switch(srcID)
		{
			case SRCID_ATV:
				return 0x84;
			case SRCID_AV1:
				return 0x85;
			case SRCID_COMPONENT1:
				return 0x89;
			case SRCID_HDMI1:
				return 0x8c;
			case SRCID_HDMI2:
				return 0x8d;
			case SRCID_HDMI3:
				return 0x8e;
			case SRCID_PC1:
				return 0x90;
			case SRCID_MEDIA:
				return 0x91;
			default:
				return 0x84;
		}
	}
	else
	{
		switch(cmdSrc)
		{
			case 0x84:
				return SRCID_ATV;
			case 0x85:
				return SRCID_AV1;
			case 0x89:
				return SRCID_COMPONENT1;
			case 0x8c:
				return SRCID_HDMI1;
			case 0x8d:
				return SRCID_HDMI2;
			case 0x8e:
				return SRCID_HDMI3;
			case 0x90:
				return SRCID_PC1;
			case 0x91:
				return SRCID_MEDIA;
			default:
				return SRCID_ATV;
		}
	}*/
	return 0;
}

int AutoTest_GetUsbPathWithPort(int port, char *usbPath)
{
	char tmpbuf[100] = {0};
	FILE *fp = NULL;
	int bFind = 0;
	int devNo, config, inf;
	float portNo = 0;
	char path[50];
	char usbway[50];
	if((fp = fopen("/etc/mtab", "r")) != NULL)
	{
		fgets(tmpbuf,100,fp); // skip line
		while(fgets(tmpbuf,100,fp) != NULL)
		{
			sscanf(tmpbuf, "%*d %*d %s %s", path, usbway);
			sscanf(path, "%d-%f:%d.%d", &devNo, &portNo, &config, &inf);

			if(portNo == port)
			{
				memcpy(usbPath, usbway, sizeof(usbway));
				bFind = 1;
				printf("copy usbPath = %s\n",usbPath);
				break;
			}
		}
		fclose(fp);
	}
	else
	{
		UMFDBG(0, "Open mtab file fail.\n");
	}
	return bFind;
}

AutoTest_USB_RESULT AutoTest_USB_Test(UINT8 devNum)
{
	AutoTest_USB_RESULT retval = AutoTest_usb_error;
	//int validdevice = 0;
	int sdPtCnt = 0;
	FILE *fp = NULL;
	char FinalBinPath[40];
	//char BinPath[MID_DISK_NAME_MAX_LEN];
	char fileTemp[30] = {0};
	char fileName[20]=	"checkusb2.bin";
	char fileCotent[30]=	"AutoTest-checkusb.bin";
	char usbroot[50] = {0};

	extern int MID_PartitionList_GetMountedCount(void);
	//extern char *MID_PartitionList_GetMountName(int index, char *pMountName);

	sdPtCnt = MID_PartitionList_GetMountedCount();
	if(sdPtCnt>0)
	{
		if(AutoTest_GetUsbPathWithPort(1,usbroot) == 1) // (2,usbroot):USB2 ; (1,usbroot):USB1
		{
			//for (validdevice = 0; validdevice < sdPtCnt; validdevice++)
			{
				//memset(BinPath, 0, 40);
				//MID_PartitionList_GetMountName(0, BinPath);

				snprintf(FinalBinPath, sizeof(FinalBinPath), "%s/%s", usbroot, fileName);

				if((fp=fopen(FinalBinPath,"rb")))
				{
					if(fgets(fileTemp, sizeof(fileTemp), fp))
					{
						if(strncmp(fileCotent, fileTemp, sizeof(fileTemp)) == 0)
							retval = AutoTest_usb_success;
						else
							retval = AutoTest_usb_no_file;
					}
					fclose(fp);
					//break;
				}
				else
					retval = AutoTest_usb_no_file;
			}
		}
		else
			retval = AutoTest_usb_no_device;
	}
	else
		retval = AutoTest_usb_no_device;

	return retval;
}

void AutoTest_SendCommand(AutoTest_SET_CMD cmd, UINT8 *pValue)
{
	UINT8 command[20] = {0};
	INT32 CRCLen = 0, headsize = sizeof(CMD_AutoTest_HEADER);
	UINT32 crc=0;

	memcpy(command, CMD_AutoTest_HEADER, headsize);

	//if(gSendAck)
	{
		switch(cmd)
		{
			case AutoTest_CMD_SetVoltageCheck:
				command[headsize] = 3;
				command[headsize+1] = AutoTest_CMD_VoltageCheck;
				break;
			case AutoTest_CMD_SetSourceCheck:
				command[headsize] = 5;
				command[headsize+1] = AutoTest_CMD_SourceCheck;
				if(pValue)
					command[headsize+2] = *(pValue);
				command[headsize+3] = 1;
				break;
			case AutoTest_CMD_SetKeyCheck:
				command[headsize] = 5;
				command[headsize+1] = AutoTest_CMD_KeyCheck;
				if(pValue)
					command[headsize+2] = *(pValue);
				command[headsize+3] = 1;
				break;
			case AutoTest_CMD_SetReset:
				command[headsize] = 4;
				command[headsize+1] = AutoTest_CMD_Reset;
				command[headsize+2] = 1;
				break;
			case AutoTest_CMD_SetHDCPKeyUpdate:
				command[headsize] = 5;
				command[headsize+1] = AutoTest_CMD_UpdateKey;
				command[headsize+2] = 0x80;
				command[headsize+3] = *(pValue);
				break;
			case AutoTest_CMD_SetUSBCheck:
				command[headsize] = 5;
				command[headsize+1] = AutoTest_CMD_USBCheck;
				command[headsize+2] = (UINT8)((gUSBTestResult>>8)&0xff);
				command[headsize+3] = (UINT8)(gUSBTestResult&0xff);
				break;
			case AutoTest_CMD_SetUpdateSW:
				command[headsize] = 4;
				command[headsize+1] = AutoTest_CMD_UpdateSW;
				if(pValue)
				{
					if(*(pValue)==UPDATE_STATE_OK)
						gUpdateResult = AutoTest_usb_success;
					else
						gUpdateResult = AutoTest_usb_error;
				}
				command[headsize+2] = (UINT8)gUpdateResult;
				break;
			case AutoTest_CMD_SetIRCheck:
				command[headsize] = 4;
				command[headsize+1] = AutoTest_CMD_IRCheck;
				command[headsize+2] = (bReceiveIRTest ? 0x81:0x80);
				break;
			case AutoTest_CMD_SetNotSupport:
				command[headsize] = 4;
				command[headsize+1] = AutoTest_CMD_NotSupport;
				command[headsize+2] = 1;
				break;
			default:
				break;
		}

		CRCLen = headsize+1+command[headsize]-2;
		crc = AutoTest_crc_check(command, CRCLen);
		command[CRCLen+1] = (UINT8)((crc>>8)&0xff);
		command[CRCLen] = (UINT8)crc&0xff;

		AutoTest_cmd_send(command, headsize+1+command[headsize]);
	}

}

void AutoTest_SourceCheck(pCON_DEV pcon, UINT8 *pValue)
{
	UINT8 cmdSrc = *(pValue+2);
	UINT8 action = *(pValue+3);

	if(action == 0)
	{
		bWaitAck = TRUE;
		if((cmdSrc>=0x84 && cmdSrc<=0x92) || cmdSrc == 0x97)
			ConCallBack(FW_FAC_TEST_SET_SOURCE, cmdSrc, 0);
		else
			gSendAck = AutoTest_ack_not_support;
		con_print((INT8 *)pValue, pcon->n-3);
	}
	else if(action == 2)
	{
		gSendAck = AutoTest_ack_none;
	}
	else
		gSendAck = AutoTest_ack_not_support;

}

//extern UINT16 ir_GetLastKPKey();

void AutoTest_KeyCheck(pCON_DEV pcon, UINT8 *pValue)
{
	//UINT8 type = *(pValue+2);
	UINT8 action = *(pValue+3);
	UINT8 key = 0;

	if(action == 0)
	{
		umfsleep(0, 300000000);
		key = (ir_GetLastKPKey()&0xff);
		AutoTest_SendCommand(AutoTest_CMD_SetKeyCheck, &key);
		gSendAck = AutoTest_ack_key;
	}
	else if(action == 2)
	{
		gSendAck = AutoTest_ack_none;
	}
	else
		gSendAck = AutoTest_ack_not_support;
}

void AutoTest_Reset(pCON_DEV pcon, UINT8 *pValue)
{
	UINT8 action = *(pValue+2);
	if(action == 0)
	{
		bSkipCmd = TRUE;

		ConCallBack(FW_AUTOTEST_RESET, 1, 0);
		gSendAck = AutoTest_ack_reset;

		//timerCount = 0;
		bSkipCmd = FALSE;
	}
	else
		gSendAck = AutoTest_ack_not_support;
}

typedef enum {
    e_MID_STATUS_NO_UPDATE,
    e_MID_STATUS_OPEN_FILE_FAILED,
    e_MID_STATUS_FORMAT_ERROR,
    e_MID_STATUS_UPDATE_SUCCESS,
}e_MID_KEYUPDATE_STATUS;

#define DIR_HDCP	      "/s2_hdcp"
#define HDCPKEY_FILE_EXTENSION ".bin"

void AutoTest_UpdateKey(pCON_DEV pcon, UINT8 *pValue)
{
	//UINT8 action = *(pValue+3);
	UINT8 type = *(pValue+2);

	if(type == 0x80)
	{
		ConCallBack(FW_FAC_UPDATE_HDCP_KEY, 1, 0);
	}
	else if(type == 0xff)
	{
		gUpdateResult = 0;
		gSendAck = AutoTest_ack_none;
	}
	else
		gSendAck = AutoTest_ack_not_support;
}

void AutoTest_USBCheck(pCON_DEV pcon, UINT8 *pValue)
{
	UINT8 action = *(pValue+3);
	UINT8 num = *(pValue+2);

	if(action == 0)
	{
		gUSBTestResult = 0;
		gUSBTestResult |= num<<8;
		gUSBTestResult |= (UINT8)AutoTest_USB_Test(((num&0xf0)+1));
		gSendAck = AutoTest_ack_usb_check;
		//AutoTest_SendCommand(AutoTest_CMD_SetUSBCheck,NULL);
	}
	else if(action == 0xff)
	{
		gSendAck = AutoTest_ack_none;
		gUSBTestResult = 0;
	}
	else
		gSendAck = AutoTest_ack_not_support;
}

void AutoTest_UpdateSW(pCON_DEV pcon, UINT8 *pValue)
{
	UINT8 action = *(pValue+2);

	if(action == 0)
	{
		ConCallBack(FW_AUTOTEST_UPDATESW, 1, 0);
	}
	else
		gSendAck = AutoTest_ack_not_support;
}

void AutoTest_IRCheck(pCON_DEV pcon, UINT8 *pValue)
{
	UINT8 action = *(pValue+2);

	if(action == 0)
	{
		gSendAck = AutoTest_ack_ir;
	}
	else if(action == 2)
	{
		bReceiveIRTest = FALSE;
		gSendAck = AutoTest_ack_none;
	}
	else
		gSendAck = AutoTest_ack_not_support;
}

/* // NOT NECESSARY NOW
void AutoTest_CIInfoCheck(pCON_DEV pcon, BYTE *pValue)
{
	BYTE action = *(pValue+2);

	if(action == 0)
	{

	}
	else if(action == 2)
		{}
}

void AutoTest_NetCheck(pCON_DEV pcon, BYTE *pValue)
{
	BYTE action = *(pValue+2);

	if(action == 0)
	{

	}
	else if(action == 2)
		{}
}

void AutoTest_WifiCheck(pCON_DEV pcon, BYTE *pValue)
{
	BYTE action = *(pValue+2);

	if(action == 0)
	{

	}
	else if(action == 2)
		{}
}

void AutoTest_LNBCheck(pCON_DEV pcon, BYTE *pValue)
{
	BYTE action = *(pValue+3);

	if(action == 0)
	{

	}
	else if(action == 2)
		{}
}
*/


Factory_CMD AutoTestCMD[]=
{
	//{AutoTest_CMD_VoltageCheck, &AutoTest_VoltageCheck},
	{AutoTest_CMD_SourceCheck, &AutoTest_SourceCheck},
	{AutoTest_CMD_KeyCheck, &AutoTest_KeyCheck},
	{AutoTest_CMD_Reset, &AutoTest_Reset},
	//{AutoTest_CMD_CIInfoCheck, &AutoTest_CIInfoCheck},
	{AutoTest_CMD_UpdateKey, &AutoTest_UpdateKey},
	//{AutoTest_CMD_NetCheck, &AutoTest_NetCheck},
	//{AutoTest_CMD_WifiCheck, &AutoTest_WifiCheck},
	//{AutoTest_CMD_LNBCheck, &AutoTest_LNBCheck},
	{AutoTest_CMD_USBCheck, &AutoTest_USBCheck},
	{AutoTest_CMD_UpdateSW, &AutoTest_UpdateSW},
	{AutoTest_CMD_IRCheck, &AutoTest_IRCheck},
};

bool AutoTest_src_parser(pCON_DEV pcon,unsigned char *msg)
	{
		//UINT8 len	= *(msg+0);
		UINT8 cmd	= *(msg+1);
		bool retval = false;
		int i=0, count = sizeof(AutoTestCMD)/sizeof(Factory_CMD);

		//con_print(&cmd, 1);
		for(i=0; i<count; i++)
		{
			if(cmd == AutoTestCMD[i].CMD_ID && !bSkipCmd)
			{
				(AutoTestCMD[i].FactoryFun)(pcon, msg);
				return TRUE;
			}
		}

		return retval;
}

void AutoTest_SetSendAck(AutoTest_ACK_TYPE SendAck)
{
	gSendAck = SendAck;
}

AutoTest_ACK_TYPE AutoTest_GetSendAck(void)
{
	return gSendAck;
}

void AutoTest_SetReceiveIRTest(UINT8 ReceiveIRTest)
{
	bReceiveIRTest = ReceiveIRTest;
}
UINT8 AutoTest_GetReceiveIRTest(void)
{
	return bReceiveIRTest;
}
#endif

#ifdef CONFIG_SUPPORT_DBX
void al_DBXTV_echo(UINT8 count, UINT8 * pdata)
{
		al_uint8 tmp[3] = "dbx";

		UARTA_Wdata.len = count+4;
		memcpy(UARTA_Wdata.buff, tmp, sizeof(tmp));
		UARTA_Wdata.buff[3] = count;
		memcpy(UARTA_Wdata.buff+4, pdata, count);

		con_send();
}

al_uint8 al_DBXTV_loadPresetFile()
{
		al_int PtCnt=0, file = 0;
		char filePath[40];
		struct stat stStatFile;
    int validdevice = 0;
		al_uint8 ret = 2;

		PtCnt = MID_PartitionList_GetMountedCount();

    for (validdevice = 0; validdevice < PtCnt; validdevice++)
    {
        memset(g_PresetFile, 0, sizeof(g_PresetFile));
        memset(filePath, 0, sizeof(filePath));
        memset((&stStatFile), 0, sizeof(struct stat));
        MID_PartitionList_GetMountName(validdevice, filePath);

        sprintf(g_PresetFile, "%s/%s", filePath, "dbx-tv_Presets.h");

        file = open(g_PresetFile, O_RDONLY);

        if ((file >= 0) && (fstat(file, &stStatFile) >= 0))
        {
        	ret = (TVFE_Audio_DBXTV_LoadPresetsFile(g_PresetFile)>0 ? 1:0);

					break;
        }
		}

		al_DBXTV_echo(1, &ret);

		return ret;
}

al_uint8 al_DBXTV_SetParamCoeff(al_uint32 ParamCoeff, al_uint32 ParamCoeffOffset, al_uint32 ParamCoeffValue)
{
	al_uint8 ret = 0;

	ret = (TVFE_Audio_DBXTV_SetParamCoeff(ParamCoeff, ParamCoeffOffset, ParamCoeffValue)>0?1:0);
	al_DBXTV_echo(1, &ret);
	return ret;
}

al_uint8 al_DBXTV_GetParamCoeff(al_uint32 ParamCoeff, al_uint32 ParamCoeffOffset)
{
	al_uint8 ret = 0, byteVal[4] ={0};
	al_uint32 ParamCoeffValue=0;

	ret = (TVFE_Audio_DBXTV_GetParamCoeff(ParamCoeff, ParamCoeffOffset, &ParamCoeffValue)>0?1:0);

	byteVal[0] =  (ParamCoeffValue>>24)&0xff;
	byteVal[1] =  (ParamCoeffValue>>16)&0xff;
	byteVal[2] =  (ParamCoeffValue>>8)&0xff;
	byteVal[3] =  ParamCoeffValue&0xff;

	al_DBXTV_echo(4, byteVal);
	return ret;
}
#endif

