/**
* Copyright(c) 2011 Sunmedia Technologies - All Rights Reserved.
*
* @file
*
* @brief this file describes teletext descriptor parsing and supports
* the interface of teletext module.
*/

#include <ctype.h>
#include <stdio.h>
#include "types.h"
#include <sys/ipc.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <msgqueue.h>
#include <unistd.h>
#include "mid_ttx_intf.h"
#include "al_basictypes.h"
#include "al_teletext.h"
#include "ai_debug_config.h"
#include "mid_siutil_dvb.h"
#include "drv_dtv_external.h"
#include "drv_dtv_common.h"
#include "kmf_ioctl.h"
#include "drv_tuner_external.h"
#include "mid_ats.h"
#include "ap_extern.h"
#include "gl_mutex.h"
#include "pvrparser.h"
#include "mid_tspl_util.h"
#include "mid_tspl_parser.h"
#include "customize.h"

#if TTX_DBG_FLAG
	#define TTX_DEBUG_MESSAGE(fmt, arg...) \
	do { \
		UMFDBG(0,"[Debug]%s: %d Line ", __FUNCTION__, __LINE__); \
		UMFDBG(0,fmt, ##arg); \
	} while(0)
#else
	#define TTX_DEBUG_MESSAGE(fmt,arg...);
#endif

#if TTX_ERROR_FLAG
	#define TTX_ERROR_MESSAGE(fmt, arg...) \
	do { \
		UMFDBG(0,"[Error]%s: %d Line\n", __FUNCTION__, __LINE__); \
		UMFDBG(0,fmt, ##arg); \
	} while(0)
#else
	#define TTX_ERROR_MESSAGE(fmt, arg...);
#endif

//#ifdef CONFIG_SUPPORT_TTX
#define TTX_MUTEX_LOCK()	{ if(g_pstTTXMutex) {GL_MutexLock(g_pstTTXMutex);}}
#define TTX_MUTEX_UNLOCK()	{ if(g_pstTTXMutex) {GL_MutexUnlock(g_pstTTXMutex);}}

#ifdef CONFIG_DTV_SUPPORT
#define MAX_TTX_NUM			(32) /**< maximal descriptor number for a stream */
#define INVALID_TTX_PID		(0x1fff) /**< invalid TTX pid */

typedef enum
{
	INITIAL_TTX_PAGE = 0x01,
	TTX_SUBTITLE_PAGE,
	ADDITIONAL_INFO_PAGE,
	PROGRAM_SCHEDULE_PAGE,
	TTX_SUBTITLE_PAGE_I,
	TTX_PAGE_MAX
} TTX_Type_t;
#endif

AL_TTX_t gALTTXCTL;
static GL_Mutex_t g_pstTTXMutex = NULL;
/**< TTX init or uninit flag */
static al_bool g_bTTXInitFlag = al_false;
#ifdef CONFIG_DTV_SUPPORT
static AL_TTX_Desc_Info_t stTTXDescInfo[MAX_TTX_NUM];
static AL_TTX_Desc_Info_t stTTXSubDescInfo[MAX_TTX_NUM];
static al_uint32 TTXSubNum = 0;
static al_uint32 TTXNum = 0;
static al_uint8 TTXDigitialLang[LANG_CODE_SIZE];
/**< TTX subtitle on or off flag */
#ifdef CONFIG_DTV_SUPPORT
static al_bool g_bTTXSubStartFlag = al_false;
#endif
static al_uint16 _u16TTXPid = INVALID_TTX_PID;
static al_int32 TTXChanHdl = INVALID_HANDLE;
#endif
static AL_TTX_Source_Type_t stTTXSourceType = AL_TTX_SOURCE_TYPE_MAX;
/**< TTX on or off flag */
static al_bool g_bTTXStartFlag = al_false;
#ifdef CONFIG_SUPPORT_PVR
static al_uint32 TTXSubtitlecurindex = 0;
#endif
static TT_Callback_f pf_TTCallback = NULL;
static TT_G0_SET new_g0 = G0_MAX_NUM;
#ifdef CONFIG_SUPPORT_TTX_PAT
static TT_MODES TTDispMode = TT_PAT_R;
#endif

#ifdef CONFIG_DTV_SUPPORT
static al_void _AI_TTX_StartRing(al_uint16 Pid)
{
	DMIOC_RINGCFG_PARAM stRingParam;
	memset(&stRingParam, 0, sizeof(DMIOC_RINGCFG_PARAM));
	stRingParam.retval = INVALID_HANDLE;
	stRingParam.DemuxUnit = 0;
	stRingParam.StreamType = DTV_TeleText;
	stRingParam.RingType = TS_DEMUX_TYPE_PES_SP;
	stRingParam.PID = Pid;
	stRingParam.Queue_ID = NULL;
	ioctl(dtvdev, DTV_IOCTL_RingConfig , &stRingParam);
	DMIOC_SETRING_PARAM stSetParam;
	memset(&stSetParam, 0, sizeof(DMIOC_SETRING_PARAM));
	stSetParam.bEnable = TRUE;
	TTXChanHdl = stRingParam.retval;
	stSetParam.Config_idx = stRingParam.retval;
	ioctl(dtvdev, DTV_IOCTL_SetRing, &stSetParam);
}

static al_void _AI_TTX_StopRing(al_int32 ChanHdl)
{
	DMIOC_SETRING_PARAM stSetParam;
	memset(&stSetParam, 0, sizeof(DMIOC_SETRING_PARAM));
	stSetParam.bEnable = FALSE;
	stSetParam.Config_idx = ChanHdl;
	ioctl(dtvdev, DTV_IOCTL_SetRing, &stSetParam);
}
#endif

/**
* @brief teletext init function.
*
* This api is used to create mutex for protecting the shared resource
* and so on.
*
* @param al_void.
*
* @return AL_SUCCESS if initialization is successful, AL_FAILURE
* otherwise.
*/
AL_Return_t AI_TTX_Init(TT_Callback_f TT_CallBack)
{
	GL_Status_t ret = GL_FAILURE;

	if(g_bTTXInitFlag)
	{
		TTX_DEBUG_MESSAGE("Teletext has been inited!\n");
		return AL_SUCCESS;
	}

	ret = GL_MutexCreate("TeletextMutex", &g_pstTTXMutex);

	if (ret != GL_SUCCESS)
	{
		TTX_ERROR_MESSAGE("Error %d:call GL_SemaphoreCreate for mutex failed!\n", ret);
		goto TTX_INIT_FAILED;
	}

	pf_TTCallback = TT_CallBack;

	g_bTTXInitFlag = al_true;

	return AL_SUCCESS;

TTX_INIT_FAILED:

	if(g_pstTTXMutex)
	{
		GL_MutexDelete(g_pstTTXMutex);
	}

	g_bTTXInitFlag = al_false;
	return AL_FAILURE;
}

/**
* @brief teletext uninit function.
*
* This api is used to delete mutex for protecting the shared resource
* and so on.
*
* @param al_void.
*
* @return AL_SUCCESS if uninitialization is successful, AL_FAILURE
* otherwise.
*/
AL_Return_t AI_TTX_Uninit(al_void)
{
	if (g_bTTXInitFlag)
	{
		if(g_pstTTXMutex)
		{
			GL_MutexDelete(g_pstTTXMutex);
			g_pstTTXMutex = NULL;
		}
		g_bTTXInitFlag = al_false;
	}
	return AL_SUCCESS;
}

/**
* @brief teletext start function.
*
* The function will create teletext decoder thread, and init slicer
* param. If the teletext type is analogue teletext, the interrupt function will be enable.
* The channel of teletext will be opened with teletext pid  and the parsing task will start
* to decode teletext page.
*
* @param SourceTyped teletext source type.
*
* @param DigitialLang digitial TTX language gotten from eeprom/flash if user setting
* on the main menu.
*
* @return AL_SUCCESS if starting is successful, AL_FAILURE
* otherwise.
*/
AL_Return_t AL_TTX_Start(AL_TTX_Source_Type_t SourceType, al_uint8 *TTXLanguage)
{
#ifdef CONFIG_DTV_SUPPORT
	al_uint32 count = 0;
#endif
	TT_MESSAGE ttMsg = {0};
#ifdef CONFIG_DTV_SUPPORT
	al_uint16 pid = INVALID_TTX_PID;
	al_uint8 TTXLang[LANG_CODE_SIZE];
#endif
	al_uint8 bInit = al_false;

	if(TTXLanguage == al_null)
	{
		return AL_FAILURE;
	}

	TTX_MUTEX_LOCK();

	if (MID_TTX_GetInitState() == al_false)
	{
		memset(&gALTTXCTL, 0, sizeof(AL_TTX_t));
		/* set call back functions to ttdecoder */
		gALTTXCTL.al_callback.change_state = pf_TTCallback;
		/* init ttdecoder and set callback functions */
		MID_TTX_init(&(gALTTXCTL.al_ctl), &(gALTTXCTL.al_callback));
		bInit = TRUE;

		TTX_DEBUG_MESSAGE("set G0 = %d\n", new_g0);
		if (gALTTXCTL.al_ctl.SetG0CharSet)
		{
			gALTTXCTL.al_ctl.SetG0CharSet(new_g0);
		}
	}

	if(g_bTTXStartFlag == al_true)
	{
		TTX_ERROR_MESSAGE("TTX has started!\n");
		goto Faile;
	}
	if(SourceType != AL_TTX_SOURCE_TYPE_MAX)
	{
		if(SourceType == AL_TTX_SOURCE_TYPE_DIGITAL)
		{
#ifdef CONFIG_DTV_SUPPORT
			for(count=0; count<TTXNum; count++)
			{
				TTXLang[0] = toupper(stTTXDescInfo[count].Language[0]);
				TTXLang[1] = toupper(stTTXDescInfo[count].Language[1]);
				TTXLang[2] = toupper(stTTXDescInfo[count].Language[2]);
				if(memcmp(TTXLang, TTXLanguage, sizeof(al_uint8)*LANG_CODE_SIZE) == 0)
				{
					pid = stTTXDescInfo[count].Pid;
					memcpy(TTXDigitialLang, TTXLang, sizeof(al_uint8)*LANG_CODE_SIZE);
					break;
				}
			}
			/** if set prefer teletext pid fail and teletext descriptor is valid,
				set default pid.*/
			if((count >= TTXNum) && (TTXNum > 0))
			{
				pid = _u16TTXPid;
			}
#ifdef CONFIG_SUPPORT_PVR
			if(MID_TSPLParser_GetThreadState())
			{
				TTX_ERROR_MESSAGE("\n[%s, %d]\n",__FUNCTION__,__LINE__);
				goto Faile;
			}
			else
#endif
			_AI_TTX_StartRing(pid);
#endif
		}
		ttMsg.mtype = TT_START_STOP;
		switch(SourceType)
		{
#ifdef CONFIG_DTV_SUPPORT
			case AL_TTX_SOURCE_TYPE_DIGITAL:
				ttMsg.command = 2;
				break;
#endif
			case AL_TTX_SOURCE_TYPE_ANALOG:
				ttMsg.command = 3;
				break;
			default:
				break;
		}
		if (gALTTXCTL.al_ctl.cmd)
		{
			gALTTXCTL.al_ctl.cmd(&ttMsg);
		}
	}
	else
	{
		TTX_ERROR_MESSAGE("invalid TTX type!\n");
		goto Faile;
	}
	g_bTTXStartFlag = al_true;

	stTTXSourceType = SourceType;

	TTX_MUTEX_UNLOCK();
	return AL_SUCCESS;

Faile:
	if (bInit)
	{
		MID_TTX_Uninit();
	}
	TTX_MUTEX_UNLOCK();
	return AL_FAILURE;
}

/**
* @brief teletext stop function.
*
* The function will suspend teletext decoder thread, reset slicer
* function. If the teletext type is analogue teletext, the interrupt
* function will be disable.
*
* @param al_void.
*
* @return AL_SUCCESS if stopping is successful, AL_FAILURE otherwise.
*/
AL_Return_t AL_TTX_Stop(al_void)
{
	TT_MESSAGE ttMsg = {0};
	printf("%s %d >>\n", __FUNCTION__, __LINE__);
	TTX_MUTEX_LOCK();
	if(g_bTTXStartFlag == al_false)
	{
		TTX_DEBUG_MESSAGE("TTX has stopped!\n");
		printf("%s %d : TTX has stopped!\n", __FUNCTION__, __LINE__);
		TTX_MUTEX_UNLOCK();
		return AL_SUCCESS;
	}
	if(stTTXSourceType != AL_TTX_SOURCE_TYPE_MAX)
	{
#ifdef CONFIG_DTV_SUPPORT
		if(stTTXSourceType == AL_TTX_SOURCE_TYPE_DIGITAL)
		{
#ifdef CONFIG_SUPPORT_PVR
			if(MID_TSPLParser_GetThreadState())
			{
				TTX_DEBUG_MESSAGE("\n========[%s, %d]\n",__FUNCTION__,__LINE__);
				printf("%s %d\n", __FUNCTION__, __LINE__);
				TTX_MUTEX_UNLOCK();
				return AL_FAILURE;
			}
			else
#endif
				if(TTXChanHdl != INVALID_HANDLE)
				{
					printf("%s %d : call _AI_TTX_StopRing\n", __FUNCTION__, __LINE__);
					_AI_TTX_StopRing(TTXChanHdl);
					printf("%s %d : call _AI_TTX_StopRing finished\n", __FUNCTION__, __LINE__);
					TTXChanHdl = INVALID_HANDLE;
				}
		}
#endif
		if (gALTTXCTL.al_ctl.cmd)
		{
			printf("%s %d : call gALTTXCTL.al_ctl.cmd\n", __FUNCTION__, __LINE__);
			ttMsg.mtype = TT_START_STOP;
			ttMsg.command = 0;
			gALTTXCTL.al_ctl.cmd(&ttMsg);
			printf("%s %d : call gALTTXCTL.al_ctl.cmd finished\n", __FUNCTION__, __LINE__);
		}
	}
	else
	{
		TTX_ERROR_MESSAGE("invalid TTX type!\n");
		TTX_MUTEX_UNLOCK();
		return AL_FAILURE;
	}
	g_bTTXStartFlag = al_false;

	stTTXSourceType = AL_TTX_SOURCE_TYPE_MAX;
#ifdef CONFIG_DTV_SUPPORT
	memset(TTXDigitialLang, 0, LANG_CODE_SIZE);
#endif
#ifdef CONFIG_DTV_SUPPORT
	if (g_bTTXSubStartFlag == al_false)
#endif
    {
		MID_TTX_Uninit();
	}
	TTX_MUTEX_UNLOCK();

	printf("<< %s %d \n", __FUNCTION__, __LINE__);
	return AL_SUCCESS;
}

/**
* @brief the function will reset teletext module, following initialization
* or a programe change.
*
* @param void.
*
* @return AL_SUCCESS if reseting is successful, AL_FAILURE
* therwise.
*/
AL_Return_t AL_TTX_Reset(al_void)
{
	TT_MESSAGE ttMsg = {0};
	TTX_MUTEX_LOCK();
#ifdef CONFIG_DTV_SUPPORT
	TTXSubNum = 0;

	TTXNum = 0;

	_u16TTXPid = INVALID_TTX_PID;

	memset(&stTTXDescInfo, 0xff, sizeof(AL_TTX_Desc_Info_t) * MAX_TTX_NUM);

	memset(&stTTXSubDescInfo, 0xff, sizeof(AL_TTX_Desc_Info_t) * MAX_TTX_NUM);
#endif
    if (g_bTTXStartFlag == al_false)
    {
		TTX_DEBUG_MESSAGE("TTX has not be started!\n");
		TTX_MUTEX_UNLOCK();
		return AL_SUCCESS;
    }
	if (MID_TTX_GetInitState() == al_false)
	{
		TTX_DEBUG_MESSAGE("TTX has not be init!\n");
		TTX_MUTEX_UNLOCK();
		return AL_SUCCESS;
	}
	ttMsg.mtype = TT_RESET;
	ttMsg.command = 1;
	if (gALTTXCTL.al_ctl.cmd)
	{
		gALTTXCTL.al_ctl.cmd(&ttMsg);
	}
	TTX_MUTEX_UNLOCK();

	return AL_SUCCESS;
}

/**
* @brief the function will start subtitle to display.
*
* The function will change teletext mode to subtitle mode, and  start to display
* subtitle on the screen. The function will create teletext decoder thread, and init
* slicer param. The demux channel of teletext channel will be opened with teletext
* pid and the subtitle page number and language will be set to middleware layer,
* and the parsing task will start to decode subtitle page.
*
* * @param Index user selects subtitle number on the subtitle menu, and using index, the special
* subtitle descriptor information will be gotten from teletext descriptor buffer.
*
* @return AL_SUCCESS if teletext subtitle starting is successful,
* AL_FAILURE otherwise.
*/
AL_Return_t AI_TTX_StartSubtitle(al_uint8 Index)
{
#ifdef CONFIG_DTV_SUPPORT
	al_uint8 number = 0;
	al_uint8 bInit = al_false;

	if(g_bTTXSubStartFlag == al_true)
	{
		TTX_ERROR_MESSAGE("TTX has started!\n");
		return AL_SUCCESS;
	}

	if(Index < TTXSubNum)
	{
		if (MID_TTX_GetInitState() == al_false)
		{
			memset(&gALTTXCTL, 0, sizeof(AL_TTX_t));
			/* set call back functions to ttdecoder */
			gALTTXCTL.al_callback.change_state = pf_TTCallback;
			/* init ttdecoder and set callback functions */
			MID_TTX_init(&(gALTTXCTL.al_ctl), &(gALTTXCTL.al_callback));
			bInit = al_true;

			TTX_DEBUG_MESSAGE("set G0 = %d\n", new_g0);
			if (gALTTXCTL.al_ctl.SetG0CharSet)
			{
				gALTTXCTL.al_ctl.SetG0CharSet(new_g0);
			}
		}

#ifdef CONFIG_SUPPORT_PVR
		if(MID_TSPLParser_GetThreadState())
        {
			al_uint32 u32PEState = MID_TSPL_MODE_MAX;
			MID_TSPLParser_GetPlayState(&u32PEState, NULL);
	    	if((u32PEState==MID_TSPL_MODE_PLAY)||(u32PEState==MID_TSPL_MODE_PAUSE)
			   ||(u32PEState==MID_TSPL_MODE_FB)||(u32PEState==MID_TSPL_MODE_FF)
			   ||(u32PEState==MID_TSPL_MODE_SF)||(u32PEState==MID_TSPL_MODE_SB))
	    	{
	            MID_TSPLParser_SetSubtitleStream(TRUE,stTTXSubDescInfo[Index].id);
	            TTXSubtitlecurindex = Index;
	    	}
			else
			{
				TTX_ERROR_MESSAGE("set ttx subtitle id error!\n");
				goto Faile;
			}
		}
		else
#endif
		{
			TT_MESSAGE ttMsg = {0};
			/*if the ttdecoder and ttslicer don't start, need start the flow.*/
			if(g_bTTXStartFlag == al_false)
			{
				ttMsg.mtype = TT_START_STOP;
				ttMsg.command = 2;
				if (gALTTXCTL.al_ctl.cmd)
				{
					gALTTXCTL.al_ctl.cmd(&ttMsg);
				}
				g_bTTXStartFlag = al_true;
				stTTXSourceType = AL_TTX_SOURCE_TYPE_DIGITAL;
			}
			ttMsg.mtype = TT_SUBTITLE;
			if (stTTXSubDescInfo[Index].MagazineNum == 0)
			{
				stTTXSubDescInfo[Index].MagazineNum = 8;
			}
			ttMsg.command = (al_int32)stTTXSubDescInfo[Index].MagazineNum*100;
			number = (stTTXSubDescInfo[Index].PageNum >> 4) & 0xf;
			if((number >= 0xa) && (number <= 0xf))
			{
				number = number - 0x0a;
			}
			ttMsg.command += (al_int32)number * 10;
			number = stTTXSubDescInfo[Index].PageNum & 0xf;
			if((number >= 0xa) && (number <= 0xf))
			{
				number = number - 0x0a;
			}
			ttMsg.command += (al_int32)number;
			if (gALTTXCTL.al_ctl.cmd)
			{
				gALTTXCTL.al_ctl.cmd(&ttMsg);
			}
		}
	}
	else
	{
		TTX_ERROR_MESSAGE("select invalid TTX subtitle index!\n");
		return AL_FAILURE;
	}
	g_bTTXSubStartFlag = al_true;
	return AL_SUCCESS;
#ifdef CONFIG_SUPPORT_PVR
Faile:
#endif
	if (bInit == al_true)
	{
		MID_TTX_Uninit();
	}
	return AL_FAILURE;
#endif

	return AL_SUCCESS;
}

/**
* @brief the function will stop subtitle to display.
*
* @param al_void.
*
* @return AL_SUCCESS if teletext subtitle stop is successful,
* AL_FAILURE otherwise.
*/
AL_Return_t AI_TTX_StopSubtitle(al_void)
{
#ifdef CONFIG_DTV_SUPPORT
	if(g_bTTXSubStartFlag == al_false)
	{
		TTX_DEBUG_MESSAGE("TTX has stopped!\n");
		return AL_SUCCESS;
	}
#ifdef CONFIG_SUPPORT_PVR
	if(MID_TSPLParser_GetThreadState())
    {
        MID_TSPLParser_SetSubtitleStream(FALSE,stTTXSubDescInfo[TTXSubtitlecurindex].id);
    }
	else
#endif
	{
		TT_MESSAGE ttMsg = {0};
		ttMsg.mtype = TT_SUBTITLE;
		ttMsg.command = 0;
		if (gALTTXCTL.al_ctl.cmd)
		{
			gALTTXCTL.al_ctl.cmd(&ttMsg);
		}
	}
	g_bTTXSubStartFlag = al_false;

	if (g_bTTXStartFlag == al_false)
	{
		MID_TTX_Uninit();
	}
#endif
	return AL_SUCCESS;
}

/**
* @brief the function will get teletext subtitle being exist or not.
*
* @param al_void.
*
* @return AL_SUCCESS if teletext subtitle is exist , AL_FAILURE
* otherwise.
*/
AL_Return_t AL_TTX_SubtitleExistStatus(al_void)
{
#ifdef CONFIG_DTV_SUPPORT
	TTX_MUTEX_LOCK();
    if (g_bTTXStartFlag == al_false)
    {
        TTX_DEBUG_MESSAGE("TTX has not be started!\n");
        TTX_MUTEX_UNLOCK();
        return AL_FAILURE;
    }

	if (MID_TTX_GetInitState() == al_false)
	{
		TTX_MUTEX_UNLOCK();
		TTX_DEBUG_MESSAGE("TTX has not be init!\n");
		return AL_SUCCESS;
	}

	if(TTX_CA_GetSubtitleExist() == 1)
	{
		TTX_MUTEX_UNLOCK();
		return AL_SUCCESS;
	}
	TTX_ERROR_MESSAGE("TTX Subtitle doesn't exist!!!\n");
	TTX_MUTEX_UNLOCK();
#endif
	return AL_FAILURE;
}

/**
* @brief the function will set key functions.
*
* If the user presses keys of teletext, the function wil be used for setting
* key function to middleware layer.
*
* @param KeyFun the functions can be set by the user pressing key.
*
* @return AL_SUCCESS if setting key function is successful, AL_FAILURE
* otherwise.
*/
AL_Return_t AL_TTX_SetKeyFunc(AL_TTX_FUNC_t KeyFun)
{
	TT_MESSAGE ttMsg = {0};
	TTX_MUTEX_LOCK();
    if (g_bTTXStartFlag == al_false)
    {
		TTX_MUTEX_UNLOCK();
        TTX_DEBUG_MESSAGE("TTX has not be started!\n");
        return AL_FAILURE;
    }
    
	if (MID_TTX_GetInitState() == al_false)
	{
		TTX_MUTEX_UNLOCK();
		TTX_DEBUG_MESSAGE("TTX has not be init!\n");
		return AL_SUCCESS;
	}

	if(KeyFun != AL_TTX_FUN_MAX)
	{
		if(KeyFun == AL_TTX_FUN_TOP_ON_MODE)
		{
			SetTopOnStatus(TRUE);
		}
		else if(KeyFun == AL_TTX_FUN_TOP_OFF_MODE)
		{
			SetTopOnStatus(FALSE);
		}
		else
		{
			switch(KeyFun)
			{
				case AL_TTX_FUN_TEXT_ON_MODE:
					ttMsg.mtype = TT_VIEWER;
					ttMsg.command = 1;
					/*cvt spec: when start to show digital TT page, need display the initial page number
					of teletext descriptor that language is matched selected language of menu item.*/
#ifdef CONFIG_DTV_SUPPORT
#ifdef SUPPORT_DISPINITPAGE_TTX
					if(stTTXSourceType == AL_TTX_SOURCE_TYPE_DIGITAL)
					{
						al_uint32 count = 0;
						al_uint8 TTXLang[LANG_CODE_SIZE];
						al_uint32 number = 0;
						for(count=0; count<TTXNum; count++)
						{
							TTXLang[0] = toupper(stTTXDescInfo[count].Language[0]);
							TTXLang[1] = toupper(stTTXDescInfo[count].Language[1]);
							TTXLang[2] = toupper(stTTXDescInfo[count].Language[2]);
							if((stTTXDescInfo[count].Pid != INVALID_TTX_PID)
							&& (memcmp(TTXDigitialLang, TTXLang, sizeof(al_uint8)*LANG_CODE_SIZE) == 0)
							&& ((stTTXDescInfo[count].Type != TTX_SUBTITLE_PAGE)
								&& (stTTXDescInfo[count].Type != TTX_SUBTITLE_PAGE_I)))
							{
								if (stTTXDescInfo[count].MagazineNum == 0)
								{
									stTTXDescInfo[count].MagazineNum = 8;
								}
								ttMsg.command = (al_int32)stTTXDescInfo[count].MagazineNum*100;
								number = (stTTXDescInfo[count].PageNum >> 4) & 0xf;
								if((number >= 0xa) && (number <= 0xf))
								{
									number = number - 0x0a;
								}
								ttMsg.command += (al_int32)number * 10;
								number = stTTXDescInfo[count].PageNum & 0xf;
								if((number >= 0xa) && (number <= 0xf))
								{
									number = number - 0x0a;
								}
								ttMsg.command += (al_int32)number;
								break;
							}
						}
					}
#endif
#endif
#ifdef CONFIG_SUPPORT_TTX_PAT
                    TTDispMode = TT_PAT_R;
                    ttMsg.pData = &TTDispMode;
#endif
					break;
				case AL_TTX_FUN_TEXT_OFF_MODE:
					ttMsg.mtype = TT_VIEWER;
					ttMsg.command = 0;
					break;
				case AL_TTX_FUN_MIX_ON_MODE:
					ttMsg.mtype = TT_TTMODES;
					ttMsg.command = TT_Mix;
					break;
				case AL_TTX_FUN_MIX_OFF_MODE:
					ttMsg.mtype = TT_TTMODES;
					ttMsg.command = TT_Normal;
					break;
				case AL_TTX_FUN_REVEAL_ON_MODE:
				case AL_TTX_FUN_REVEAL_OFF_MODE:
					ttMsg.mtype = TT_REVEAL;
					ttMsg.command = 0;
					break;
				case AL_TTX_FUN_SUBTITLE_ON_MODE:
					ttMsg.mtype = TT_SUBTITLE;
					ttMsg.command = 1;
					break;
				case AL_TTX_FUN_SUBTITLE_OFF_MODE:
					ttMsg.mtype = TT_SUBTITLE;
					ttMsg.command = 0;
					break;
				case AL_TTX_FUN_SIZE_UP:
				case AL_TTX_FUN_SIZE_DOWN:
				case AL_TTX_FUN_SIZE_NORMAL:
					ttMsg.mtype = TT_SIZE;
					ttMsg.command = 0;
					break;
				case AL_TTX_FUN_SIZE_LEFT:
					break;
				case AL_TTX_FUN_SIZE_RIGHT:
					break;
				case AL_TTX_FUN_SIZE_RIGHT_UP:
					break;
				case AL_TTX_FUN_SIZE_RIGHT_DOWN:
					break;
				case AL_TTX_FUN_HOLD_ON:
				case AL_TTX_FUN_HOLD_OFF:
					ttMsg.mtype = TT_HOLD;
					ttMsg.command = 0;
					break;
				case AL_TTX_FUN_CONCEAL_ON:
					ttMsg.mtype = TT_CANCEL;
					ttMsg.command = 1;
					break;
				case AL_TTX_FUN_CONCEAL_OFF:
					ttMsg.mtype = TT_CANCEL;
					ttMsg.command = 0;
					break;
				case AL_TTX_FUN_SUBTITLE_CONCEAL_ON:
					break;
				case AL_TTX_FUN_SUBTITLE_CONCEAL_OFF:
					break;
				case AL_TTX_FUN_RED:
					ttMsg.mtype = TT_SELECT_LINK;
					ttMsg.command = 0;
					break;
				case AL_TTX_FUN_GREEN:
					ttMsg.mtype = TT_SELECT_LINK;
					ttMsg.command = 1;
					break;
				case AL_TTX_FUN_YELLOW:
					ttMsg.mtype = TT_SELECT_LINK;
					ttMsg.command = 2;
					break;
				case AL_TTX_FUN_BLUE:
					ttMsg.mtype = TT_SELECT_LINK;
					ttMsg.command = 3;
					break;
				case AL_TTX_FUN_INDEX:
					ttMsg.mtype = TT_MAIN_INDEX;
					ttMsg.command = 0;
					break;
				case AL_TTX_FUN_SUBCODE_MENU_ON:
				case AL_TTX_FUN_SUBCODE_MENU_OFF:
					ttMsg.mtype = TT_SUBCODE;
					ttMsg.command = 0;
					break;
				case AL_TTX_FUN_PAGE_UP:
					ttMsg.mtype = TT_UP_DOWN_KEYS;
					ttMsg.command = 1;
					break;
				case AL_TTX_FUN_PAGE_DOWN:
					ttMsg.mtype = TT_UP_DOWN_KEYS;
					ttMsg.command = -1;
					break;
				case AL_TTX_FUN_SUBCODE_PAGE_UP:
					ttMsg.mtype = TT_LEFT_RIGHT_KEYS;
					ttMsg.command = 1;
					break;
				case AL_TTX_FUN_SUBCODE_PAGE_DOWN:
					ttMsg.mtype = TT_LEFT_RIGHT_KEYS;
					ttMsg.command = -1;
					break;
				case AL_TTX_FUN_LIKE_PAGE_ON:
					ttMsg.mtype = TT_FOND_MODE;
					ttMsg.command = 1;
					break;
				case AL_TTX_FUN_LIKE_PAGE_OFF:
					ttMsg.mtype = TT_FOND_MODE;
					ttMsg.command = 0;
					break;
				default:
					break;
			}
			TTX_DEBUG_MESSAGE("TT_SendMsg mtype = %d, command = %d\n", ttMsg.mtype, ttMsg.command);
			if (gALTTXCTL.al_ctl.cmd)
			{
				gALTTXCTL.al_ctl.cmd(&ttMsg);
			}
		}
		TTX_MUTEX_UNLOCK();
		return AL_SUCCESS;
	}

	TTX_MUTEX_UNLOCK();

	return AL_FAILURE;

}

/**
* @brief search subtitle page function.
*
* When starting to display subtitle on the screen with pressing subtitle key,
* it needs direct the search mode.
* For example: when the teletext is displaying on the screen and the search
* mode is "AL_TT_DIRECTION_UP", if the user presses subtitle key, the
* display mode will be changed to subtitle mode and the subtitle data
* will be gotten by searching minimal to maximum subtitle page.
*
* @param Direct the search mode.
* @param *DisplayPage 
* when mode is AL_TTX_DIRECTION_DISP, DisplayPage is page number by user.
* otherwise gotten current display teletext subtitle page number.
*
* @return AL_SUCCESS if searching subtitle page is successful, AL_FAILURE
* otherwise.
*/
AL_Return_t AL_TTX_SearchSubtitlePage(AL_TTX_Search_Direction_t Direct, AL_TTX_Page_t *DisplayPage)
{
    int magno = 0, pgno = 0, subno = 0;
    TT_MESSAGE ttMsg = {0};

	TTX_MUTEX_LOCK();
    if (g_bTTXStartFlag == al_false)
    {
		TTX_MUTEX_UNLOCK();
        TTX_DEBUG_MESSAGE("TTX has not be started!\n");
        return AL_FAILURE;
    }
    
    if (!DisplayPage)
    {
		TTX_MUTEX_UNLOCK();
        TTX_ERROR_MESSAGE("Invalid parameter~~~\n");
        return AL_INVALID_PARAM;
    }
    
	if (MID_TTX_GetInitState() == al_false)
	{
		TTX_MUTEX_UNLOCK();
		TTX_DEBUG_MESSAGE("TTX has not be init!\n");
		return AL_SUCCESS;
	}

	switch(Direct)
	{
		case AL_TTX_DIRECTION_UP:
			ttMsg.mtype = TT_SUB_UP_DOWN_KEYS;
			ttMsg.command = 1;
			break;
		case AL_TTX_DIRECTION_DOWN:
			ttMsg.mtype = TT_SUB_UP_DOWN_KEYS;
			ttMsg.command = -1;
			break;
        case AL_TTX_DIRECTION_DISP:
            ttMsg.mtype = TT_SUBTITLE_PAGE;
			ttMsg.command = DisplayPage->PageNum;
            break;
		default:
			break;
	}
	TTX_DEBUG_MESSAGE("TT_SendMsg mtype = %d, command = %d\n", ttMsg.mtype, ttMsg.command);
	if(gALTTXCTL.al_ctl.cmd)
	{
		gALTTXCTL.al_ctl.cmd(&ttMsg);
	}
	gALTTXCTL.al_ctl.GetCurDispPageno(&magno, &pgno, &subno);
	magno = ((magno == 0)? 8: magno);
    if (Direct == AL_TTX_DIRECTION_DISP)
    {
        al_uint16 page = magno * 100 + pgno;
        if (DisplayPage->PageNum != page)
        {
            TTX_ERROR_MESSAGE("\nPageNum:%d, page:%d\n",DisplayPage->PageNum, page);
            TTX_MUTEX_UNLOCK();
            return AL_FAILURE;
        }
    }
    else
    {
        DisplayPage->PageNum = (((al_uint16)magno)<<8) | (al_uint16)pgno;
        DisplayPage->SubPageNum = (al_uint16)subno;
        /*invalid page number*/
        if((DisplayPage->PageNum == 0x7ff) && (DisplayPage->SubPageNum == 0x3f7f))
        {
            TTX_MUTEX_UNLOCK();
            return AL_FAILURE;
        }
    }
	TTX_MUTEX_UNLOCK();
	return AL_SUCCESS;
}

/**
* @brief set digital entry function.
*
* If the user presses the "0-9" keys while teletext is displaying on the screen,
* displayed teletext page number will be changed to the number by user setting.
*
* @param DigitalEntry the "0-9" keys.
*
* @return AL_SUCCESS if setting digital entry is successful, AL_FAILURE otherwise.
*/
AL_Return_t AL_TTX_SetDigitalEntry(al_uint8 DigitalEntry)
{
	TTX_MUTEX_LOCK();
    if (g_bTTXStartFlag == al_false)
    {
		TTX_MUTEX_UNLOCK();
        TTX_DEBUG_MESSAGE("TTX has not be started!\n");
        return AL_FAILURE;
    }
    
	if (MID_TTX_GetInitState() == al_false)
	{
		TTX_MUTEX_UNLOCK();
		TTX_DEBUG_MESSAGE("TTX has not be init!\n");
		return AL_SUCCESS;
	}

	TT_MESSAGE ttMsg = {0};
	ttMsg.mtype = TT_NUMBER_KEYS;
	ttMsg.command = DigitalEntry;

	TTX_DEBUG_MESSAGE("TT_SendMsg mtype = %d, command = %d\n", ttMsg.mtype, ttMsg.command);
	if (gALTTXCTL.al_ctl.cmd)
	{
		gALTTXCTL.al_ctl.cmd(&ttMsg);
	}
	TTX_MUTEX_UNLOCK();
	return AL_SUCCESS;
}

/**
* @brief set analog teletext language function.
*
* If the user can set analogue teletext language on the mainmenu, the set
* teletext language will be stored to EEPROM or FLASH. If analogue teletext
* needs be displayed on the screen, the stored analogue teletext language will
* be set to teletext decoder module. The teletext decoder thread
* starts to parse data with the set analogue teletext language, otherwise parse
* data with the initial analogue teletext language.
*
* @param TeletextLang set analog teletext language.
*
* @return AL_SUCCESS if setting language is successful, AL_FAILURE otherwise.
*/
AL_Return_t AL_TTX_SetLanguage(AL_TTX_LANG_t TeletextLang)
{
    if (g_bTTXStartFlag == al_false)
    {
        TTX_DEBUG_MESSAGE("TTX has not be started!\n");
        return AL_FAILURE;
    }
	switch(TeletextLang)
	{
		case AL_TTX_LANG_WEST_EUROPEAN:
			new_g0 = G0_WEST_EUR;
			break;
		case AL_TTX_LANG_GREEK:
			new_g0 = G0_GREEK;
			break;
		case AL_TTX_LANG_EAST_EUROPEAN:
			new_g0 = G0_EAST_EUR;
			break;
		case AL_TTX_LANG_ARABIC:
			new_g0 = G0_ARAB;
			break;
		case AL_TTX_LANG_CYRILLIC:
			new_g0 = G0_CYRILLIC;
			break;
		case AL_TTX_LANG_RUSSIAN:
			new_g0 = G0_RUSSIA;
			break;
		case AL_TTX_LANG_HEBREW:
			new_g0 = G0_HEBREW;
			break;
		case AL_TTX_LANG_FARSI:
			new_g0 = G0_FARSIAN;
			break;
		case AL_TTX_LANG_CENTRAL_EUROPEAN:
			break;
		case AL_TTX_LANG_WEST_EUROPEAN_TURKISH:
			new_g0 = G0_TURKEY;
			break;
		case AL_TTX_LANG_BYELORUSSIAN:
			new_g0 = G0_BYELORUSSIAN;
			break;
		case AL_TTX_LANG_RUSSIA2:
			new_g0 = G0_RUSSIA2;
			break;
        case AL_TTX_LANG_THAI:
            new_g0 = G0_THAI;
            break;
		case AL_TTX_LANG_MAX:
		default:
			break;
	}
    TTX_MUTEX_LOCK();
	TTX_DEBUG_MESSAGE("set G0 = %d\n", new_g0);
    if (MID_TTX_GetInitState() != false)
    {
    	if (gALTTXCTL.al_ctl.SetG0CharSet)
    	{
    		gALTTXCTL.al_ctl.SetG0CharSet(new_g0);
    	}
    }
	TTX_MUTEX_UNLOCK();
	return AL_SUCCESS;
}

/**
* @brief the function will get teletext data being valid or not.
*
* Before teletext parsing, teletext needs be preparsing. If gotten datas
* are some errors, the datas with preparsing don't be stored
* to cache buffer, and the teletext function of sysapp layer don't work.
*
* @param *Status gotten the signal status value. if the preparsing is
* successful, the gotten signal status is al_true, else if the preparsing
* is false, the gotten signal status is al_false.
*
* @return AL_SUCCESS if gotten signal is successful, AL_FAILURE
* therwise.
*/
AL_Return_t AL_TTX_GetSignalStatus(al_bool *Status)
{
	if(Status == al_null)
	{
		return AL_FAILURE;
	}
    
    if (g_bTTXStartFlag == al_false)
    {
        TTX_DEBUG_MESSAGE("TTX has not be started!\n");
        return AL_FAILURE;
    }
    /*Don't support to display teletext because free memory isn't enough.*/
#ifdef CONFIG_SUPPORT_64M_DTV
#ifndef CONFIG_SUPPORT_TTX_PAT
    Status = al_false;
	return AL_SUCCESS;
#endif
#endif
	TTX_MUTEX_LOCK();
	if(stTTXSourceType == AL_TTX_SOURCE_TYPE_ANALOG)
	{
		if (MID_TTX_GetInitState() == al_false)
		{
			TTX_MUTEX_UNLOCK();
			TTX_DEBUG_MESSAGE("TTX has not be init!\n");
			return AL_SUCCESS;
		}

		*Status = al_false;
		if (gALTTXCTL.al_ctl.GetPageCount)
		{
			if (gALTTXCTL.al_ctl.GetPageCount() > 0) {
				*Status = al_true;
			}
		}
	}
#ifdef CONFIG_DTV_SUPPORT
	if(stTTXSourceType == AL_TTX_SOURCE_TYPE_DIGITAL)
	{
		/*some ts include teletext descriptor without source data.*/
		if(TTXNum > 0)
		{
			*Status = al_true;
		}
	}
#endif
	TTX_MUTEX_UNLOCK();
	return AL_SUCCESS;
}

/**
* @brief the function can get the parsed teletext descriptor information.
*
* After creating subtitle menu with pressing subtitle key, the subtitle menu
* with all subtitle types is shown on the screen. So when displayed information
* is inited, the parsed teletext subtitle descriptor information will be gotten.
*
* @param TTXDescType teletext descriptor type.
*
* @param Index using the index can get special teletext subtitle descriptor information
* from the buffer.
*
* @param *TeletextDescInfo it will store the gotten teletext subtitle descriptor
* information.
*
* @return AL_SUCCESS if getting teletext subtitle descriptor information is successful,
* AL_FAILURE otherwise.
*/
AL_Return_t AL_TTX_GetDescInfo(AL_TTX_Desc_Type_t TTXDescType, al_int Index, AL_TTX_Desc_Info_t *TTXDescInfo)
{
#ifdef CONFIG_DTV_SUPPORT
	if((TTXDescInfo == al_null) || (TTXDescType == AL_TTX_DESC_MAX))
	{
		return AL_FAILURE;
	}

	TTX_MUTEX_LOCK();
	if(TTXDescType == AL_TTX_SUB_DESC_TYPE)
	{
		if((al_uint32)Index <= TTXSubNum)
		{
			memcpy(TTXDescInfo, &stTTXSubDescInfo[Index], sizeof(AL_TTX_Desc_Info_t));
			TTX_MUTEX_UNLOCK();
			return AL_SUCCESS;
		}
	}
	else
	{
		if((al_uint32)Index <= TTXNum)
		{
			memcpy(TTXDescInfo, &stTTXDescInfo[Index], sizeof(AL_TTX_Desc_Info_t));
			TTX_MUTEX_UNLOCK();
			return AL_SUCCESS;
		}
	}

	TTX_MUTEX_UNLOCK();
#endif
 	return AL_FAILURE;
}

/**
* @brief the function can get file ts teletext subtitle information from pe module
*
* when play recorded file, if need to display teletext subtitle on the screen, the file ts
* teletext subtitle information need to be gotten from pe module.
*
* @param SubInfo the subtitle information will be getton from PE module.
*
* @return AL_SUCCESS if getting file ts teletext subtitle information is successful,
* AL_FAILURE otherwise.
*/
AL_Return_t AI_TTX_GetFileTsSubInfo(AL_TTX_Desc_Info_t SubInfo)
{
#ifdef CONFIG_DTV_SUPPORT
	if(TTXSubNum < MAX_TTX_NUM)
	{
		al_uint8 i;
		for(i=0; i<TTXSubNum; i++)
		{
			if(memcmp(&SubInfo, &stTTXSubDescInfo[i], sizeof(AL_TTX_Desc_Info_t)) == 0)
			{
				return AL_FAILURE;
			}
		}
		memcpy(&stTTXSubDescInfo[TTXSubNum], &SubInfo, sizeof(AL_TTX_Desc_Info_t));
		TTXSubNum++;
		return AL_SUCCESS;
	}
#endif
	return AL_FAILURE;
}

/**
* @brief the function can get the valid teletext or teletext subtitle descriptor total number.
*
* Before the teletext subtitle module starts to work, it needs get the subtitle descpritor
* total number. If the total number is more than 0, the subtitle module will start
* to work, otherwise stop to work.
*
* @param TTXDescType teletext descriptor type.
*
* @param *GetTotalNum get the teletext or teletext subtitle descriptor total number.
*
* @return AL_SUCCESS if getting total number is successful,
* AL_FAILURE otherwise.
*/
AL_Return_t AL_TTX_GetTotalNum(AL_TTX_Desc_Type_t TTXDescType, al_uint32 *GetTotalNum)
{
#ifdef CONFIG_DTV_SUPPORT
	if((GetTotalNum == al_null) || (TTXDescType == AL_TTX_DESC_MAX))
	{
		return AL_FAILURE;
	}
	TTX_MUTEX_LOCK();
	if(TTXDescType == AL_TTX_DESC_TYPE)
	{
		*GetTotalNum = TTXNum;
	}
	else
	{
		*GetTotalNum = TTXSubNum;
	}

	if(*GetTotalNum <= 0)
	{
		//TTX_ERROR_MESSAGE("Get invalid TTX Subtitle total number!\n");
		TTX_MUTEX_UNLOCK();
		return AL_FAILURE;
	}

 	TTX_MUTEX_UNLOCK();
#endif
 	return AL_SUCCESS;
}

/**
* @brief the function can get file ts teletext information from pe module
*
* when play recorded file, if need to display teletext on the screen, the file ts
* teletext information need to be gotten from pe module.
*
* @param al_void.
*
* @return AL_SUCCESS if getting file ts teletext information is successful,
* AL_FAILURE otherwise.
*/
#ifdef CONFIG_SUPPORT_PVR
AL_Return_t AL_TTX_GetFileTsTTXInfo(al_void)
{
#ifdef CONFIG_DTV_SUPPORT
	al_int Ret = 0;
	al_uint Subtitle_Num = 0;
    al_int subtitle_id = 0;
	al_uint i = 0;
    TS_SUB_PG_t Subtitle_Program_Info = {0};

	TTX_MUTEX_LOCK();

    MID_TSPLParser_GetTotalSubtitleStreamCount(&Subtitle_Num);
    for (i = 0; i < Subtitle_Num; i++)
    {
        memset(&Subtitle_Program_Info, 0x0, sizeof(TS_SUB_PG_t));
		subtitle_id = MID_TSPL_PVR_GetSubtitleID(i);
        Ret = MID_TSPLParser_GetSubtitleAttribute(i,&Subtitle_Program_Info);
        if ((Ret != 0)
			&& (Subtitle_Program_Info.type != TS_SUBTITLE_TTX))
        {
            continue;
        }
		if(Subtitle_Program_Info.type == TS_SUBTITLE_TTX)
		{
			stTTXDescInfo[TTXNum].id = subtitle_id;
			stTTXDescInfo[TTXNum].Pid = Subtitle_Program_Info.pid;
			stTTXDescInfo[TTXNum].Type = Subtitle_Program_Info.ttx.teletext_type;
			stTTXDescInfo[TTXNum].MagazineNum = Subtitle_Program_Info.ttx.teletext_magazine_number;
			if(stTTXDescInfo[TTXNum].MagazineNum == 0)
			{
				stTTXDescInfo[TTXNum].MagazineNum = 8;
			}
			stTTXDescInfo[TTXNum].PageNum = Subtitle_Program_Info.ttx.teletext_page_number;
			memcpy(stTTXDescInfo[TTXNum].Language, Subtitle_Program_Info.ttx.ISO_639_language_code,
				sizeof(al_uint8)*LANG_CODE_SIZE);
			TTXNum++;
		}
    }
	TTX_MUTEX_UNLOCK();
#endif
    return AL_SUCCESS;
}
#endif

/**
* @brief the function can parse teletext descriptor in PMT.
*
* After parsing PMT, PSI listener will start to work. When the stream
* type is private data of PES packet, the teletext descriptor will be parsing.
* When parsing the teletext descriptor, the information: teletext pid, teletext
* language, teletext type, teletext magazine number and page number will be
* stored to teletext buffer.
*
* @param *Data teletext descpriptor data.
*
* @param DataLen the number of bytes of descriptors.
*
* @param Pid teletext pid.
*
* @return AL_SUCCESS if parsing teletext descriptor is successful,
* AL_FAILURE otherwise.
*/
AL_Return_t AI_TTX_ParseDesc(al_uint8 *Data, al_uint16 DataLen, al_uint16 Pid)
{
#ifdef CONFIG_DTV_SUPPORT
	al_uint8 u8DescTag = 0;
	al_uint8 u8DescLen = 0;
	al_uint8 u8DescPos = 0;
	al_uint16 u16Pos = 0;
	al_bool bRedundantFlag = al_false;
	al_uint32 i = 0;
	AL_TTX_Desc_Info_t TTXDescInfo = {0};

	if(Data == al_null)
	{
		return AL_FAILURE;
	}
	TTX_MUTEX_LOCK();
	while (u16Pos < DataLen && TTXNum < MAX_TTX_NUM)
	{
		u8DescTag = Data[u16Pos++];
		u8DescLen = Data[u16Pos++];
		if (u8DescTag == DESCR_TELETEXT)
		{
			_u16TTXPid = Pid;
			u8DescPos = 0;
			if (u8DescLen == 0)
			{
				TTXNum++;
			}
			else
			{
				while (((u8DescPos + 5) <= u8DescLen) && (TTXNum < MAX_TTX_NUM))
				{
					memset(&TTXDescInfo, 0, sizeof(AL_TTX_Desc_Info_t));
					/**< get teletext pid */
					TTXDescInfo.Pid = Pid;
					/**< get teletext language */
					memcpy(TTXDescInfo.Language, Data + u16Pos + u8DescPos, sizeof(al_uint8)*LANG_CODE_SIZE);
					u8DescPos += 3;
					/**< get teletext type */
					TTXDescInfo.Type = (Data[u16Pos + u8DescPos] & 0xF8) >> 3;
					/**< get teletext magazine number */
					TTXDescInfo.MagazineNum = Data[u16Pos + u8DescPos] & 0x07;
					if(TTXDescInfo.MagazineNum == 0)
					{
						TTXDescInfo.MagazineNum = 8;
					}
					/**< get teletext page number */
					TTXDescInfo.PageNum = Data[u16Pos + u8DescPos + 1];
					u8DescPos += 2;

					/**< check redundant content */
					bRedundantFlag = al_false;
					for(i=0; i<TTXNum; i++)
					{
						if(memcmp(&stTTXDescInfo[i], &TTXDescInfo, sizeof(AL_TTX_Desc_Info_t)) == 0)
						{
							bRedundantFlag = al_true;
							break;
						}
					}
					if(bRedundantFlag == al_false)
					{
						memcpy(&stTTXDescInfo[TTXNum], &TTXDescInfo, sizeof(AL_TTX_Desc_Info_t));
						TTXNum++;
					}
					/**< teletext subtitle */
					if (TTXDescInfo.Type == TTX_SUBTITLE_PAGE
						|| TTXDescInfo.Type == TTX_SUBTITLE_PAGE_I)
					{
						/**< check redundant content */
						bRedundantFlag = al_false;
						for (i=0; i <TTXSubNum; i++)
						{
							if(memcmp(&stTTXSubDescInfo[i], &TTXDescInfo, sizeof(AL_TTX_Desc_Info_t)) == 0)
							{
								bRedundantFlag = al_true;
								break;
							}
						}
						if(bRedundantFlag == al_false)
						{
							memcpy(&stTTXSubDescInfo[TTXSubNum], &TTXDescInfo, sizeof(AL_TTX_Desc_Info_t));
							TTXSubNum++;
						}
					}
				}
			}
		}
		u16Pos += u8DescLen;
	}
	TTX_MUTEX_UNLOCK();
#endif
	return AL_SUCCESS;
}

/**
* @brief the function can set subtitle display window freezed or not.
*
* After the video is freezed with pressing freeze key, if the subtitle is
* displaying on the screen, the subtitle needs be freezed. Else the
* video isn't freezed with pressing freeze key again,  if the subtitle is
* displaying on the screen, the subtitle needn't be freezed.
*
* @param FreezeStatus if freeze is true, the subtitle needs be freezed.
* Else if freeze is false, the subtitle needn't be freezed.
*
* @return al_void.
*/
al_void AI_TTX_SetSubtitleFreeze(al_bool FreezeStatus)
{
    if (g_bTTXStartFlag == al_false)
    {
        TTX_DEBUG_MESSAGE("TTX has not be started!\n");
        return;
    }
    
	if (MID_TTX_GetInitState() == al_false)
	{
		TTX_DEBUG_MESSAGE("TTX has not be init!\n");
	}

	TT_MESSAGE ttMsg = {0};
	ttMsg.mtype = TT_HOLD;
	ttMsg.command = 0;
	if (gALTTXCTL.al_ctl.cmd)
	{
		gALTTXCTL.al_ctl.cmd(&ttMsg);
	}
}


/**
* @brief get wss data function
*
* This api is used to get wss data from ttdecoder.
*
* @param al_void.
*
* @return wss data.
*/
al_uint16 AI_TTX_GetWSSData(al_void)
{
    if (g_bTTXStartFlag == al_false)
    {
        TTX_DEBUG_MESSAGE("TTX has not be started!\n");
        return AL_FAILURE;
    }
    
	if (MID_TTX_GetInitState() == al_false)
	{
		TTX_DEBUG_MESSAGE("TTX has not be init!\n");
		return AL_SUCCESS;
	}

	if (gALTTXCTL.al_ctl.GetWSSData)
	{
		return gALTTXCTL.al_ctl.GetWSSData();
	}
	return 0;
}

/**
* @brief get TTX time data
*
* @param buff: data buffer
*
* @param buff_size: buffer size
*
* @return AL_SUCCESS if getting time string is successful,
* AL_FAILURE otherwise.
*/
AL_Return_t AI_TTX_GetTimeData(al_uint8 *buff, al_uint8 buff_size)
{
	if ((buff == al_null) || (buff_size < 9)) {
		return AL_FAILURE;
	}
    
    if (g_bTTXStartFlag == al_false)
    {
        TTX_DEBUG_MESSAGE("TTX has not be started!\n");
        return AL_FAILURE;
    }
    
	if (MID_TTX_GetInitState() == al_false)
	{
		TTX_DEBUG_MESSAGE("TTX has not be init!\n");
		return AL_SUCCESS;
	}

	TT_MESSAGE ttMsg = {0};
	ttMsg.mtype = TT_QUERY_TIME;
	ttMsg.command = buff_size;
	ttMsg.pData = buff;
	if (gALTTXCTL.al_ctl.cmd)
	{
		gALTTXCTL.al_ctl.cmd(&ttMsg);
	}
	return AL_SUCCESS;
}

/**
* @brief refresh page
*
* @param al_void.
*
* @return AL_SUCCESS if refresh page successful,
* AL_FAILURE otherwise.
*/
AL_Return_t AL_TTX_RefreshPage(al_void)
{
    if (g_bTTXStartFlag == al_false)
    {
        TTX_DEBUG_MESSAGE("TTX has not be started!\n");
        return AL_FAILURE;
    }
	if (MID_TTX_GetInitState() == al_false)
	{
		TTX_DEBUG_MESSAGE("TTX has not be init!\n");
		return AL_SUCCESS;
	}

	MID_TTX_RefreshPage();
	return AL_SUCCESS;
}


//#endif

