#include <sys/prctl.h>
#include <stdlib.h>
#include <pthread.h>
#include "al_console.h"
#include "al_console_customer.h"
#include "kmf_ioctl.h"
#include "ap_extern.h"
#include "umf_ir.h"
#include "drv_uart_def.h"
#include "util_ioctl.h"
#include "customize.h"
#ifdef SUPPORT_FACTORY_AUTO_TEST_MODE4
#include "mid_tvfe.h"
#endif

#ifdef CONFIG_CTV_UART_FAC_MODE
#include "al_console_CtvRs232.h"
#endif

#ifdef CONFIG_INN_UART_FAC_MODE
#include "al_console_inn_rs232.h"
#endif

#ifdef CONFIG_HK_UART_FAC_MODE
#include "al_console_HkRs232.h"
#endif

#ifdef CONFIG_TPV_UART_FAC_MODE
#include "al_console_TpvRs232.h"
#endif

#ifdef CONFIG_CTV_UART_FAC_MODE
#define UARTCatchDelay 10000000 //10ms
#else
#define UARTCatchDelay 200000000 //10ms
#endif

#ifdef CONFIG_CTV_UART_FAC_MODE
#define UARTCommandHeadLen 6
#else
#define UARTCommandHeadLen 2
#endif


CON_DEV con_dev_t;
CON_DBG con_dbg = {0};
CON_UART con_uart = {0};

Ser8250_IOData UARTA_Wdata;

bool PQ_Tool = FALSE;
int uartafd = 0;
char RSTMP[256] = {0};

con_Header_Parse_t con_Header_Parse = NULL;

#if defined(SUPPORT_FACTORY_AUTO_TEST_MODE4)
UINT8 CMD_AutoTest_HEADER[3] = {0xaa,0xa7,0x5a};
extern bool AutoTest_src_parser(pCON_DEV pcon,unsigned char *msg);

extern UINT8 gSendAck;
#endif
pthread_mutex_t	uartA_Lock =  PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t  uartA_Strat = PTHREAD_COND_INITIALIZER;
pthread_mutex_t	uartB_Lock =  PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t  uartB_Strat = PTHREAD_COND_INITIALIZER;

enum {
    UartA,
    UartB,
};

//extern char usbroot[20];
#if 0
static void con_SetDbgOn(UINT8 value)
{
	con_dbg.DbgEnable = value;
}
static void con_SetDbgOSDPos(UINT8 value)
{
	con_dbg.DbgOSDPos = value;
}

static void con_SetDbgMsgtoUSB(UINT8 value)
{
	con_dbg.DbgMsgtoUSB = value;
}
#endif

UINT8 con_CalcChecksum(int len,UINT8 *msg)
{
	int i;
	UINT8 sum=0;

	for(i=0;i<len;i++)
	{
		sum += msg[i];
	}

	return sum;
}

void con_SetDbgMsgtoUSB(UINT8 value)
{
	con_dbg.DbgMsgtoUSB = value;
}

void con_ShowHexValuetoOSD(UINT8 bTx, UINT8 len, UINT8 *pStr)
{
	// need menu to draw OSD
	/*if(con_dbg.DbgEnable)
	{
		if(bTx)
		{
			CTL_ShowUmfHex(con_dbg.DbgOSDPos, len, con_dbg.Rxlen, pStr, con_dbg.Rx);
			con_dbg.Txlen = len;
			memcpy(con_dbg.Tx, pStr, con_dbg.Txlen);
		}
		else
		{
			CTL_ShowUmfHex(con_dbg.DbgOSDPos, con_dbg.Txlen, len, con_dbg.Tx, pStr);
			con_dbg.Rxlen = len;
			memcpy(con_dbg.Rx, pStr, con_dbg.Rxlen);
		}
	}*/
	
}

extern char *MID_PartitionList_GetMountName(int index, char *pMountName);
void con_SaveDbgMsgtoUSB(unsigned char bTx, short len, unsigned char *pStr)
{
	INT8 UsbitMapPath[128]={0};
	INT8 DateString[32]={0};
	INT8 UsbRootPath[32]={0};
	time_t currsec;
	UINT8 fileName[10]="RSdbg";
	FILE *fp = NULL;
    struct tm* p = NULL;
	int i = 0;
    
	if(con_dbg.DbgMsgtoUSB)
	{
		time(&currsec);
        p = localtime(&currsec);
        if(p)
        {
		    strftime(DateString, sizeof(DateString), "%Y-%m-%d %H.%M.%S", p);
        }
		MID_PartitionList_GetMountName(0, UsbRootPath); // 0 menas always write debug message to the first usb.
		snprintf(UsbitMapPath, 128, "%s%s%s%s", UsbRootPath, "/", fileName, ".txt");
		
		fp = fopen(UsbitMapPath,"a+");
        
        if (!fp)
        {
            return;
        }
		if(bTx == RS_Sx) // save umf debug message to usb flash 
		{
			if(con_dbg.DbgMsgtoUSB == RSDBG_UMF || con_dbg.DbgMsgtoUSB == RSDBG_ALL)
			{
				fprintf(fp,"%s Sx ", DateString);
				fprintf(fp,"%s ", pStr);
				memset(RSTMP, 0x0, 256);
				fprintf(fp,"\r\n");
				fflush(fp);
			}
		}
		else // save console debug message to usb flash 
		{
			if(con_dbg.DbgMsgtoUSB == RSDBG_CONSOLE || con_dbg.DbgMsgtoUSB == RSDBG_ALL)
			{
				if(bTx == RS_Tx)
				{
					fprintf(fp,"%s Tx ", DateString);
				}
				else if(bTx == RS_Rx)
				{
					fprintf(fp,"%s Rx ", DateString);
				}
				else if(bTx == RS_Dx)
				{
					fprintf(fp,"%s Dx ", DateString);
				}
				else
					fprintf(fp,"%s Ex ", DateString);
				
				for(i = 0; i < len ; i++)
				{
					fprintf(fp,"%02x ", *(pStr+i));
				}
				
				fprintf(fp,"\r\n");
				fflush(fp);
			}
		}
		
		//umfsleep(0, 10000000);
		fclose(fp);
        sync();
	}
}

pCON_DEV get_pCON_DEV(void)
{
	return &con_dev_t;
}

int console_find_pid(char *name)
{
	FILE *fp = NULL;
	char line[64], fin = 0;
	int ret = -1;
	
	system("ps > /tmp/pslog");
	fp = fopen("/tmp/pslog","r");
    
    if (!fp)
    {
        printf("\n=====[%s, %d] fopen fail~~~\n",__FUNCTION__,__LINE__);
        return ret;
    }
    
	while(!fin && fgets(line,64,fp) != NULL)
	{
		if(strstr(line, name)!=NULL)
		{
			fin = 1;
			ret = atoi(line);
		}						
	}
    
	fclose(fp);
	system("rm -f /tmp/pslog");
	return ret;
}


void sigfunc(int sig)
{
	pCON_DEV pcon = &con_dev_t;
    if(freopen("/dev/null", "r",pcon->in) == NULL)
    {
        printf("[al console]Fail to freopen /dev/null\n");
    }
}

void con_print(/*pCON_DEV pcon,*/char* str ,int size)
{
	int /*i = 0,*/ count = 0, outsize = 0;

	outsize = size;
	/*
	if(pcon->bConnectViaUSB == true)
	{
		for(i = 0; i < size; i++)
		{
			fprintf(pcon->out,"%c",*(str+i));
		}
		fflush(pcon->out);
	}
	else*/
	{
		while(1)
		{
			UARTA_Wdata.len = (outsize >= UART_BUF_SIZE)?UART_BUF_SIZE:outsize;
			memcpy(UARTA_Wdata.buff, (str + count * UART_BUF_SIZE), UARTA_Wdata.len);
			ioctl(uartafd, SiS_UART_WRITE, &UARTA_Wdata);
			//con_ShowHexValuetoOSD(RS_Rx, UARTA_Wdata.len, UARTA_Wdata.buff);
			//con_SaveDbgMsgtoUSB(RS_Rx, UARTA_Wdata.len, UARTA_Wdata.buff);

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

struct timespec time_diff(struct timespec start, struct timespec end)
{
	struct timespec temp;
	if ((end.tv_nsec-start.tv_nsec)<0)
	{
		temp.tv_sec = end.tv_sec-start.tv_sec-1;
		temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
	}
	else
	{
		temp.tv_sec = end.tv_sec-start.tv_sec;
		temp.tv_nsec = end.tv_nsec-start.tv_nsec;
	}
	return temp;
}

void tv_SetXONXOFF(INT8 value) //PQ tool use to set XONXOFF
{
	ioctl(kmfdev, KMF_IOC_XONXOFF, value);
}

void con_debug_msg(UINT8 value)
{
	UINT8 tmp[2] = {0xAA, 0xAA};

	tmp[1] = value;
	
	con_SaveDbgMsgtoUSB(RS_Dx, 2, tmp);
}

void con_listener(void* argv, int param)
{
	pCON_DEV pcon = (pCON_DEV)argv;
	struct termios mode, old_mode;
	struct timespec c_ts,p_ts,tt;
	UINT8 tmp[MAX_CMD_LENGTH] = {0};
	UINT8 ch = 0;
	bool  bLeave = false, bReset = false;
	unsigned int len = 0;

	Ser8250_IOData UARTA_data = {0};
	char retval = 0;
#if defined(SUPPORT_FACTORY_AUTO_TEST_MODE4)
	unsigned int totalsize = 0, headsize = 0;
	UINT32 result = 0, tmpCrc = 0;
	UINT8 status = 0;
#endif
//#ifdef SUPPORT_SFU_AUTO_TEST
	UINT8 checksum = 0;
	unsigned int i = 0;
//#endif
	
	#ifdef CONFIG_SUPPORT_DBX
	al_uint32 offset = 0, dbxVal = 0;
	#endif
	memset(&UARTA_data, 0x0, sizeof(Ser8250_IOData));
	bLeave = false;
	if(pcon->bConnectViaUSB == true)
	{
		pcon->in = fopen("/dev/ttyUSB0","r");
		pcon->out = fopen("/dev/ttyUSB0","w");
		pcon->dbg = fopen("/dev/ttyS0","w");
		//pcon->dbg = fopen("/dev/null","w");
		if(NULL != pcon->dbg)
		{
			condbg2(pcon->dbg,"start to open /dev/ttyUSB0\n");
		}
		if(pcon->in == NULL || pcon->out == NULL)
		{
			if(NULL != pcon->dbg)
			{
				condbg2(pcon->dbg,"Fail to open /dev/ttyUSB0\n");
			}
			pcon->bActive = false;
			return;
		}
		tcgetattr(fileno(pcon->in), &old_mode);
		tcgetattr(fileno(pcon->in), &mode);
		cfmakeraw(&mode);
		tcsetattr(fileno(pcon->in), TCSANOW, &mode);
	}
	else
	{
		uartafd = open("/dev/console", O_RDWR);
		pcon->dbg = fopen("/dev/ttyS1","w");
		Cmd_mmio_WriteUINT32(0xbe0d0014, 0x00004ccd); //set baud rate 115200
		if(uartafd <= 0)
		{
			if(NULL != pcon->dbg)
			{
				condbg2(pcon->dbg,"Open Console Fail \n");
			}
		}
	}
	tv_SetXONXOFF(FALSE); // its needs to set XON/XOFF to 0 after openning console or ttyUSB0
	pcon->n = 0;
	pcon->pid = getpid();
	if(pcon->bConnectViaUSB == true)
		(void)signal(73,sigfunc);

    if(NULL != pcon->dbg)
    {
	    condbg2(pcon->dbg,"Start to receive data\n");
    }

#ifdef CONFIG_QSD 
  // increase LVDS swing level
	system("byte 0xbe00011c 0x69");
	system("byte 0xbe00011d 0x6");
	#ifdef CONFIG_CHIP_531
	// add for new LVDS line 
		system("word 0xbe1cc1b8 0x270dc");
		system("word 0xbe1cc1b8 0x270dd");
	#endif
#endif

	clock_gettime(CLOCK_REALTIME, &c_ts);
	p_ts.tv_sec = c_ts.tv_sec;
	p_ts.tv_nsec = c_ts.tv_nsec;

#if defined(SUPPORT_FACTORY_AUTO_TEST_MODE4)
		if(param == 1)
		{
			//gSendAck |= AutoTest_ack_voltage_check;
			AutoTest_SendCommand(AutoTest_CMD_SetVoltageCheck, NULL);
			umfsleep(0, 100000000);
			AutoTest_SendCommand(AutoTest_CMD_SetVoltageCheck, NULL);
			umfsleep(0, 100000000);
			AutoTest_SendCommand(AutoTest_CMD_SetVoltageCheck, NULL);
			umfsleep(0, 100000000);
			AutoTest_SendCommand(AutoTest_CMD_SetVoltageCheck, NULL);
			umfsleep(0, 100000000);
			AutoTest_SendCommand(AutoTest_CMD_SetVoltageCheck, NULL);
		}
#endif

    unsigned int commandlen = 0;
	while(pcon->bActive)
	{
		if(pcon->bConnectViaUSB == true)
		{
			ch = fgetc(pcon->in);
		}
		else
		{
			while (1)
			{	
				memset(&UARTA_data, 0x0, sizeof(Ser8250_IOData));
				con_uart.UART_UARTA_Listen_Status = TRUE;
				retval = ioctl(uartafd, SiS_UART_READ, &UARTA_data);
				if(retval >= 0 || con_uart.uartA_Stop)
				{
				 	con_uart.UART_UARTA_Listen_Status = FALSE;
					break;
				}
				
			}
		}

		if (!pcon->bActive)
		{
			con_uart.uartA_Stop = TRUE;
			tv_SetXONXOFF(TRUE);
			ioctl(uartafd, SiS_UART_STOP, UARTA_data);
			break;
		}	
		
		p_ts.tv_sec = c_ts.tv_sec;
		p_ts.tv_nsec = c_ts.tv_nsec;
		clock_gettime(CLOCK_REALTIME, &c_ts);

		tt = time_diff(p_ts,c_ts);

		if( (tt.tv_sec > 0) || (tt.tv_sec == 0 && tt.tv_nsec > 200000000) )
		{
			// Timeout
			//condbg2(pcon->dbg,"timeout %ld sec %ld nsec\n",tt.tv_sec,tt.tv_nsec);
			//condbg2(pcon->dbg,"*** Time Out: %d %d *** \n", (int)tt.tv_sec, (int)tt.tv_nsec);
			//condbg2(pcon->dbg,"*** Time Last: %d %d *** \n", (int)p_ts.tv_sec, (int)p_ts.tv_nsec);
			//condbg2(pcon->dbg,"*** Time Now: %d %d *** \n", (int)c_ts.tv_sec,(int)c_ts.tv_nsec);
			//con_debug_msg(0x1);
			pcon->n = 0;
		}
		
		if(pcon->bConnectViaUSB == true)
		{
			tmp[pcon->n] = ch;
			pcon->n++;
		}
		else
		{		
		/*
			if(UARTA_data.len == 0)
			{
				condbg2(pcon->dbg,"*** UARTA_data->len = 0 *** \n");
			}
			*/
			if((pcon->n + UARTA_data.len) <= MAX_CMD_LENGTH)
			{
			    if (UARTA_data.len < MAX_BUFFER_SIZE)
                {         
    				memcpy(&tmp[pcon->n], UARTA_data.buff, UARTA_data.len);
    				pcon->n += UARTA_data.len;
                }
                else
                {
    				memcpy(&tmp[pcon->n], UARTA_data.buff, MAX_BUFFER_SIZE);
    				pcon->n += MAX_BUFFER_SIZE;
                }
			}
			else
			{
			    if ((MAX_CMD_LENGTH - pcon->n) >= MAX_BUFFER_SIZE)
                {
                    memcpy(&tmp[pcon->n], UARTA_data.buff, MAX_BUFFER_SIZE);
                    pcon->n += MAX_BUFFER_SIZE;
                }
                else
                {
                    memcpy(&tmp[pcon->n], UARTA_data.buff, (MAX_CMD_LENGTH - pcon->n));
                    pcon->n += (MAX_CMD_LENGTH-pcon->n);
                }
			}
			memset(&UARTA_data.buff, 0, UARTA_data.len);
			UARTA_data.len = 0;
//#ifndef CONFIG_AC_SPECIAL_FILE_CHECK		
			p_ts.tv_sec = c_ts.tv_sec;
			p_ts.tv_nsec = c_ts.tv_nsec;
			if(param!=1 && param!=0xff)
			{
				do{
						con_uart.UART_UARTA_Listen_Status = TRUE;

                        if (con_Header_Parse!= NULL )
                        {
                            if ((commandlen == 0) && pcon->n >= UARTCommandHeadLen)
                            {
                                con_Header_Parse(tmp, pcon->n, &commandlen);
                            }

                            if (commandlen != 0 && pcon->n >= commandlen)
                            {
                                break;
                            }
                        }
                        
						retval = ioctl(uartafd, SiS_UART_TRYREAD, &UARTA_data);
						
						if(retval >= 0 && UARTA_data.len > 0)
						{
							if((pcon->n + UARTA_data.len) <= MAX_CMD_LENGTH)
							{
                                if (UARTA_data.len < MAX_BUFFER_SIZE)
                               {
    								memcpy(&tmp[pcon->n], UARTA_data.buff, UARTA_data.len);		
    								pcon->n += UARTA_data.len;
                                }
                                else
                                {
                                    memcpy(&tmp[pcon->n], UARTA_data.buff, MAX_BUFFER_SIZE);
                                    pcon->n += MAX_BUFFER_SIZE;
                                }
							}
							else
							{
                                if ((MAX_CMD_LENGTH - pcon->n) >= MAX_BUFFER_SIZE)
                                {
    								memcpy(&tmp[pcon->n], UARTA_data.buff, MAX_BUFFER_SIZE);
    								pcon->n += MAX_BUFFER_SIZE;
                                }
                                else
                                {
    								memcpy(&tmp[pcon->n], UARTA_data.buff, (MAX_CMD_LENGTH - pcon->n));
    								pcon->n += (MAX_CMD_LENGTH - pcon->n);
                                }
							}
							memset(&UARTA_data, 0x0, sizeof(Ser8250_IOData));
						}
						clock_gettime(CLOCK_REALTIME, &c_ts);
						tt = time_diff(p_ts,c_ts);
				}while(tt.tv_nsec<UARTCatchDelay && pcon->n<MAX_CMD_LENGTH);
				con_uart.UART_UARTA_Listen_Status = FALSE;
			}
			//con_ShowHexValuetoOSD(RS_Tx, pcon->n, tmp);
//#endif
		}
		#ifdef CONFIG_INN_UART_FAC_MODE
		if(con_InnRs232_CheckSyncAndValid(tmp[0],pcon->n))
		{
			con_InnRs232_AutoTest_parser(pcon,tmp);
			bReset = true;
		}
		else
		#endif
		{
		switch(tmp[0])
		{
		#ifdef CONFIG_QSD
			case 's': // for QSD test using
				if(tmp[1] == 'r' && tmp[2] == 'c' && tmp[3] == 0x20)
				{
					if(tmp[4] == 's' || tmp[4] == 'p')
						len = 6;
					else if(tmp[4] == 'a')
					{
						if (tmp[5] == 't')
							len = 13;
						else if (tmp[5] == 'n')
							len = 11;
					}
					else if(tmp[4] == 'd')
						len = 13;
					else if(tmp[4] == 'c')
						len = 8;
					else if(tmp[4] == 'h' || tmp[4] == 'j' || tmp[4] == 'm')
						len = 9;
					else if(tmp[4] == 'l')
						len = 7;
					if(len == pcon->n)
					{
						bLeave = !con_src_parser(pcon,(unsigned char*)(tmp+4));
						bReset = true;
					}
				}
				break;
			case 'q':
				if(tmp[1] == 's' && tmp[2] == 'l' && tmp[3] == 't' && tmp[4] == '.')
				{
					if (tmp[5] == 'h')	// hdmi
					{
						len = 10;
					}
					else if(tmp[5] == 'p') // pc
					{
						len = 7;
					}
					else if(tmp[5] == 's') // svideo or scart
					{
						if (tmp[6] == 'c' || tmp[6] == 'v' )
							len = 11;
					}					
					else if(tmp[5] == 'a') //av1 or atv
					{
						if (tmp[6] == 'v' || tmp[6] == 't' )
							len = 8;
					}
					else if(tmp[5] == 'd') //dtv
					{
						len = 8;
					}	
					else if(tmp[5] == 'm') // mmio
					{
						len = 9;
					}
					else if(tmp[5] == 'y') //ypbpr
					{
						len = 10;
					}
					else if(tmp[5] == 'j') // jpeg
					{
						len = 9;
					}
					else if(tmp[5] == 'f') // dtv && set frequency
					{
						len = 9;	
					}				
					else if(tmp[5]=='n')
					{
						len = 10;	
					}
					
					if(len == pcon->n)
					{
						bLeave = !con_new_src_parser(pcon,(unsigned char*)(tmp+5));
						bReset = true;
					}
				}
				break;
				
			case 0x0D:
				con_echo1(pcon, 'S', 'T');
				con_echo1(pcon, 'A', 'R');
				con_echo1(pcon, 'T', 0x0);
				bReset = true;
				break;
		#endif		
			case CMD_SIS_SYNC:
				len = tmp[1] * 256 + tmp[2];
				
				if(len == pcon->n)
				{
					checksum = 0;
					for(i = 0; i < len-1; i++)
					{
						checksum += tmp[i];
					}

					bReset = true;
					if(checksum == tmp[len-1])
					{
						con_SaveDbgMsgtoUSB(RS_Tx, pcon->n, tmp);
						bLeave = !con_SIS_parser(pcon,(UINT8*)(tmp+1));
					}
					else
					{
						con_echo1(pcon, 0xFF, 0xFF); // checksum error
						con_echo1(pcon, checksum, tmp[len-1]);
						con_debug_msg(0x2);
					}
				}
				break;
#ifdef SUPPORT_CONSOLE_AUTO_TEST
			case CMD_AUTOTEST_SYNC_AA:
			case CMD_AUTOTEST_SYNC_AB:
				len = tmp[1];			
				if(((len != 0xfe)&&(len == pcon->n))
				   || ((len == 0xfe)&&(pcon->n == (unsigned int)((tmp[2]<<8)|(tmp[3])))))
				{
					bLeave = !con_autotest_parser(pcon,(UINT8*)(tmp));
					//con_print((char*)tmp, pcon->n);
				}
				bReset = true;
				break;
#endif
			
#if defined(SUPPORT_FACTORY_AUTO_TEST_MODE4)
			case 0xaa:
				headsize = sizeof(CMD_AutoTest_HEADER);
				if(tmp[0] == CMD_AutoTest_HEADER[0] && tmp[1] == CMD_AutoTest_HEADER[1] && tmp[2] == CMD_AutoTest_HEADER[2])//!memcmp(tmp, CMD_AutoTest_HEADER, headsize))
				{
					totalsize = (unsigned int)(headsize+1+tmp[headsize]);
					if(pcon->n == totalsize) //check length
					{
						result = tmp[totalsize-1];
						result = (result<<8 & 0xff00) | tmp[totalsize-2];
						if((tmpCrc=AutoTest_crc_check(tmp, totalsize-2)) == result) // check crc
						{
							if(!AutoTest_src_parser(pcon, &tmp[headsize]))
								gSendAck = AutoTest_ack_not_support;
						}
						else
							gSendAck = AutoTest_ack_not_support;
						bReset = true;
					}
				}
				
				break;
#endif
#ifdef SUPPORT_SFU_AUTO_TEST
			case CMD_SFU_Set_TvConnenction: // for SFU Auto Test
			case CMD_SFU_Set_SymbolRate:
			case CMD_SFU_Set_SpecifiedChannel:		
			case CMD_SFU_Get_MosaicStatus:
				len = (tmp[0]>>5) & 0x07;
				if(len == pcon->n)
				{
					checksum = 0;
					for(i = 0; i < len; i++)
					{
						checksum += tmp[i];
					}
					if((checksum & 0xFF) == 0xFF)
					{
						bLeave = !con_suf_parser(pcon,(UINT8*)(tmp));
						bReset = true;
					}
					else
					{
						UINT8 echodata[7]="\n err \n";// checksum error
						con_echo_sfu(7,echodata);
					}
				}
				break;
#endif

			case 'd':
				#ifdef CONFIG_SUPPORT_DBX
				offset = 0;
				if(!strncmp((char *)tmp, "dbx",3) && pcon->n ==12)
				{
					if(con_CalcChecksum(8, tmp+4) == tmp[3])
					{
						if(tmp[4]==DBXTV_SetParamCoeff)
						{
							offset = (tmp[6] << 8 | tmp[7]);
							dbxVal = (tmp[8]<<24 | tmp[9]<<16 | tmp[10]<<8 | tmp[11]);
							al_DBXTV_SetParamCoeff(tmp[5], offset, dbxVal);
						}
						else
						{
							UINT8 echodata[7] = "no cmd";
   	     					con_echo_sfu(sizeof(echodata), echodata);
						}
					}
					else
					{
						UINT8 echodata[8] = "crc err1"; // checksum error
       					con_echo_sfu(sizeof(echodata), echodata);
					}
					bReset = true;
				}
				else if(!strncmp((char *)tmp, "dbx",3) && pcon->n ==8 && tmp[4]!=DBXTV_SetParamCoeff)
				{
					if(con_CalcChecksum(4, tmp+4) == tmp[3])
					{
						switch(tmp[4])
						{
							case DBXTV_LoadPresetsFile:
								al_DBXTV_loadPresetFile();
								bReset = true;
								break;
							case DBXTV_GetParamCoeff:
								offset = (tmp[6] << 8 | tmp[7]);
								al_DBXTV_GetParamCoeff(tmp[5], offset);
								bReset = true;
								break;
							default:
								{
									al_uint8 echodata[7] = "no cmd"; // checksum error
               					 con_echo_sfu(sizeof(echodata), echodata);
									bReset = true;
								}
								break;
						}
					}
					else
					{
						al_uint8 echodata[8] = "crc err2"; // checksum error
        				con_echo_sfu(sizeof(echodata), echodata);
						bReset = true;
					}

				}
				else if(pcon->n > 8 && tmp[4]>DBXTV_SetParamCoeff)
					bReset = true;
		#else
		if(tmp[1] == 'e' && tmp[2] == 'm' && tmp[3] == 'o' && tmp[4] == 'd')
		{
			bLeave = FALSE;
			len = con_ats_parser(pcon,(UINT8*)(tmp));
			if(len == FALSE)
			{
				bReset = false;
			}
			else
			{
				bReset = true;
			}
		}
		#endif
				break;
#ifdef CONFIG_TPV_UART_FAC_MODE
            case TPV_RS232_HEAD:
#ifdef TPV_DEBUG	
                con_echo_sfu_Save2Usb((UINT32)(pcon->n), tmp);
#endif
                con_TpvRs232_AutoTest_parser(pcon, (UINT8*)tmp, pcon->n);
                bReset = true;
                break;
#endif
				
#ifdef CONFIG_CTV_UART_FAC_MODE
            case ACCUVIEW_RS232_AutoTest_HEAD:
#ifdef CTV_DEBUG	
                con_echo_sfu_Save2Usb((UINT32)(pcon->n), tmp);
#endif
                //con_AccuviewRs232_AutoTest_parser(pcon, (UINT8*)(tmp + 1), pcon->n);
				con_AccuviewRs232_Demux_KeyData_Packets(pcon, (UINT8*)tmp, pcon->n);
                bReset = true;
                break;
#endif
#ifdef CONFIG_HK_UART_FAC_MODE
			case CMD_HK_SYNC_80:
				con_HkRs232_AutoTest_parser(pcon, (UINT8*)tmp);
                bReset = true;
                break;
#endif
			default:
				
				if(pcon->n >= 3)
				{
					if(pcon->n>=16)
					{
						if(tmp[1] == 0x00)
						{
							con_echo(pcon,0);
						}
						else if(tmp[1] == 0x01)
						{
							con_echo(pcon,1);
							bLeave = TRUE;
						}
						
					}
				#ifdef SUPPORT_FACTORY_AUTO_TEST_MODE4
					else 
					{
						MID_TVFE_GetSpecialFileStatus(&status);
						if(status && (tt.tv_nsec > 0))
							gSendAck = AutoTest_ack_not_support;
						//bReset = true;
					}
				#endif
					bReset = true;
				}
				break;
		}
		}

		if(pcon->n >= MAX_CMD_LENGTH)
		{
			bReset = TRUE;//modify for tmp[pcon->n] overrun-buffer-arg
		}
		if(bReset)
		{
			bReset = false;
			memset(&tmp, 0, MAX_CMD_LENGTH);
			pcon->n = 0;
			len = 0xFFFF;
			retval = 0;
            commandlen = 0;
		}

		if(bLeave || !pcon->bActive)
		{
			pcon->bActive = FALSE; // for UART B to leave its while loop
			con_uart.uartA_Stop = TRUE;
			tv_SetXONXOFF(TRUE);
			ioctl(uartafd, SiS_UART_STOP, UARTA_data);
			break;
		}
	}
	condbg2(pcon->dbg,"bye!!\n");
	pcon->pid = 0;

	if(pcon->bConnectViaUSB == true)
	{
		tcsetattr(fileno(pcon->in), TCSADRAIN, &old_mode);
		fclose(pcon->in);
		fclose(pcon->out);
	}
	else
	{	
	    if(uartafd > 0)
        {   
		    close(uartafd);
        }
	}
	fclose(pcon->dbg);
}

static UINT8 CONSOLE_Get_UART_Listener_Status(UINT8 uartType)
{
	return (uartType == UartA)?con_uart.UART_UARTA_Listen_Status:con_uart.UART_UARTB_Listen_Status;
}

static UINT8 CONSOLE_Get_UART_Wait_Status(UINT8 uartType)
{
	return (uartType == UartA)?con_uart.UART_UARTA_Wait_Status:con_uart.UART_UARTB_Wait_Status;
}

static void con_Register_Header_Parse_Init()
{

    con_Header_Parse = 
#if defined(CONFIG_CTV_UART_FAC_MODE)
        NULL;//con_AccuviewRs232_HeaderParse;
#elif defined(SUPPORT_CONSOLE_AUTO_TEST)
        con_autotest_HeaderParse;
#elif defined(SUPPORT_SFU_AUTO_TEST)
        NULL;
#else 
        NULL;
#endif
}

#if 0
static UINT8 CONSOLE_Get_UART_Close(UINT8 uartType)
{
	return (uartType == UartA)?con_uart.uartA_Thread_close:con_uart.uartB_Thread_close;
}
static UINT8 CONSOLE_GET_UART_STATUS(UINT8 uartType)
{
	return (uartType == UartA)?con_uart.uartA_Thread:con_uart.uartB_Thread;

}
static void CONSOLE_UARTA_Listenser_Ready(void)
{
	while(1)
	{
		if(CONSOLE_Get_UART_Listener_Status(UartA))
		{
			break;
		}
		else
		{
			umfsleep(0, 50000000);
		}
	}
}

#endif
void CONSOLE_UART_START(UINT8 uartType)
{
	(uartType == UartA)?pthread_cond_signal(&uartA_Strat):pthread_cond_signal(&uartB_Strat);
}



INT32 CONSOLE_EXIT(void)
{
	pCON_DEV pcon = &con_dev_t;
	Ser8250_IOData UARTA_Data = {0};

	while(con_uart.uartA_Thread)
	{
		if(CONSOLE_Get_UART_Listener_Status(UartA) || CONSOLE_Get_UART_Wait_Status(UartA) )
		{
			pcon->bActive = FALSE;
			con_uart.uartA_Thread = FALSE;
			con_uart.uartA_Stop = TRUE;
			do
			{
				if(CONSOLE_Get_UART_Listener_Status(UartA))
				{
					ioctl(uartafd, SiS_UART_STOP, &UARTA_Data);
					break;
				}
				else if(CONSOLE_Get_UART_Wait_Status(UartA))
				{
					CONSOLE_UART_START(UartB);
					CONSOLE_UART_START(UartA);
					break;
				}
				else
				{
					umfsleep(0, 50000000);
				}
			}while(1);
			break;
		}
		else
		{
			umfsleep(0, 100000000);
		}
	}
	umfsleep(0, 50000000);

	if(pcon->bConnectViaUSB == true)
	{
		if(pcon->pid) kill(pcon->pid,73);
	}

	return 0;
}

void CONSOLE_MODE(int mode)
{
	pCON_DEV pcon = &con_dev_t;
	if(pcon->bActive == false)
	{
		pcon->bConnectViaUSB = (mode == RS232_USB_MODE)?true:false;
	}
	else
	{
		condbg("Console is connected, set mode when it is disconnected.\n");
	}
}

#ifdef CONFIG_CTV_UART_FAC_MODE
pthread_t Rs232Thread = 0;
#endif

void CONSOLE_INIT(void *arg)
{
	pCON_DEV pcon = &con_dev_t;
	int param = 0;
    int err = 0;

	if(arg)
		param = *((int *)arg);
	
	con_uart.uartA_Thread_close = FALSE;
	con_uart.uartA_Thread = TRUE;
	prctl(PR_SET_NAME , "CONSOLE_INIT", NULL, NULL, NULL);	

#ifdef CONFIG_CTV_UART_FAC_MODE
    size_t stacksize = 64*1024; 
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setstacksize(&attr, stacksize);
    if (pthread_create(&Rs232Thread, &attr, (void *) AccuviewRs232StartTask, (void*)(&Rs232Thread)) != 0)
    {
        printf("AccuviewRs232StartTask pthread_create fail \n");
    }
	pthread_attr_destroy(&attr);
#endif

    con_Register_Header_Parse_Init();

    do{	
		pthread_mutex_lock(&uartA_Lock);
		con_uart.uartA_Stop = FALSE;
		pcon->bActive = TRUE;
		pcon->pid = 0;
	
		con_listener(pcon, param);
		
		if(con_uart.uartA_Thread)
		{
			 con_uart.UART_UARTA_Wait_Status = TRUE;
			 err = pthread_cond_wait(&uartA_Strat, &uartA_Lock);
             if (err != 0) 
             {
                 printf("pthread_cond_wait error return %d\n", err);
             }        
             
			 con_uart.UART_UARTA_Wait_Status = FALSE;
		}
		
		pthread_mutex_unlock(&uartA_Lock);
	}while(con_uart.uartA_Thread);
	
	con_uart.uartA_Thread_close = TRUE;
	//return 0;
}

