/*
 * mtx_sample.c
 * 動画テクスチャサンプル
 */

/* Standards */
#include <stdint.h>

/* uC3 */
#include "kernel.h"
#include "com.h"
#include "ffsys.h"

#include "mtx_sample.h"
#include "mtx_movie.h"
#include "mtx_gfx.h"
#include "sample_common.h"
#include "AG903_regmap.h"
#include "AG903_intno.h"
#include "../dsp/dsp_common.h"

/* ライブラリ */
#include "int/intmgr.h"
#include "bmu/bmumgr.h"
#include "dsp/dspmgr.h"
#include "timr/timrmgr.h"
#include "osp/ospmgr.h"
#include "sys/spcprm.h"
#include "sys/sscprm.h"

/* エラー処理関連 */
#define RTNCODE					gMTXErrCode
#define ERRCHK(chk,syntax)		do{ RTNCODE=syntax; if (chk!=RTNCODE) MTX_ErrPrintf("ERROR: %s():L%u\r\n",__func__,__LINE__); }while(0)

/* 関数プロトタイプ */
static int32_t MTX_Help();
static int32_t MTX_Demo();
static int32_t MTX_setupDisplay(void);

/* MPS関連 */
static void TimerHandler(AG903_TIMRMgrHandle *handle);
static void DisplayHandler(void);

static int32_t (*func[])() = {
	MTX_Help,
	MTX_Demo,
};


extern bool						gFlagMPSDone;		/* 動画処理終了フラグ */
extern bool						gFlagGFXDone;		/* 描画処理終了フラグ */
extern bool						gFlagGFXFlip;		/* 描画完了フラグ */
extern ER_ID					gID_MPL_GFX;		/* 描画用MPL ID */
extern gvdFatalErrorInfo		gFatal;								/* 致命的エラー保持用 */
extern mpsOutBufInfo			gOutbufinfo[MTX_MOV_OUTBUF_COUNT];	/* 出力バッファ情報 */
extern AG903_SPCPrmPllnParam	DSP_SAMPLE_PLL[];
extern AG903_DSPMgrSyncParam	DSP_SAMPLE_SYNCPARAM[];


int32_t gMTXErrCode		= AG903_ENONE; /* エラーチェック用 */
bool	gFlagExit;				/* サンプル終了フラグ */
ER_ID	gAsyncTaskID	= -1;	/* 非同期処理タスクID */
ER_ID	gMovieTaskID	= -1;	/* 動画再生処理タスクID */
ER_ID	gGFXTaskID		= -1;	/* 描画処理タスクID */
ID		gID_IRQ_DSP		= -1;

static	void		*gWindowAttributeAddr	= NULL;	/* ウィンドウアトリビュートアドレス保持用 */
static	void		*gOSPBufferAddr 		= NULL;	/* OSP管理バッファアドレス */

/* ライブラリハンドラ */
AG903_DSPMgrHandle	*MTX_dsp_handle		= NULL;
AG903_TIMRMgrHandle	*MTX_tim_handle		= NULL;
AG903_BMUMgrHandle	*MTX_bmu_handle[2]	= {NULL};
AG903_OSPMgrHandle	*MTX_osp_handle		= NULL;


/* タスク */
/* 動画再生処理用タスク */
void movie_tsk(VP_INT);
static const T_CTSK ctsk_movie = {
	TA_HLNG | TA_ACT | TA_FPU, (VP_INT)0, (FP)movie_tsk, 7, 0x800, 0, "Movie"
};

/* 描画処理用タスク */
void gfx_tsk(VP_INT);
static const T_CTSK ctsk_gfx = {
	TA_HLNG | TA_ACT | TA_FPU, (VP_INT)0, (FP)gfx_tsk, 6, 0x800, 0, "GFX"
};

/* 関数 */
void MTX_main(uint8_t param)
{
	((void)param);

	int32_t		rc = AG903_ENONE;
	uint8_t		mode = 0;
	char		input[2+2];

	/* 共通初期化処理 */
	rc = sys_meminit(AG903_SAMPLE_VRAM_ALLOC_SIZE-MTX_GFX_HEAP_SIZE-0x10000,
					 (void *)AG903_SAMPLE_VRAM_ADDR,
					 SYSMEM_NORMAL_CACHE_OFF);

	if (rc == AG903_ENONE) {
		size_t size;
		sys_memspace(&size);
		MTX_Printf("[Memory] sys_memspace : %u [Byte]\r\n", size);
	} else {
		MTX_ErrPrintf("ERROR: System memory init failed.\r\n");
	}

	func[0](); /* Help */
	while (mode != 0xFF) {
		MTX_Printf(" -- Choose sample number (00h<HELP> to FFh): ");
		COM_GetNum_Wait(input, sizeof(input));
		mode = (ASCtoBIN(input[0]) << 4)
			   | (ASCtoBIN(input[1]) << 0);

		if(0xFF == mode) {
			break;
		}
		if(mode >= (sizeof(func)/sizeof(void*))) {
			func[0](); /* Help */
		}
		else {
		   	Board_SelectDviTX();	/* DVI出力有効 */
			func[mode]();	/* Sample func実行 */
		}
	}

	/* 共通終了処理 */
	sys_memfinal();

	return;
}

static int32_t MTX_Help(void)
{
	MTX_Printf("\t# 00 ... Help\r\n");
	MTX_Printf("\t# 01 ... Movie Texture Sample\r\n");
	MTX_Printf("\t# FF ... Exit Sample\r\n");
	return AG903_ENONE;
}

static int32_t MTX_Demo(void)
{
	gFlagExit = false;

	mpsConfig *mpsconf = MPS_getConfig();

	MTX_Printf("\n"
			   "[MOVIE TEXTURE SAMPLE]\n"
			   "\n");
	MTX_Printf("Setting start >>>\n");

	/* File system */
	{
		ER ercd;

		ercd = mountp('A', 0, (ID)Fsif_GetDevid(FSIF_DEV_CF)); /* CF->'A' */
		if (ercd != E_OK) {
			MTX_ErrPrintf("ERROR: CF mount failed.\r\n");
			return ercd;
		}
	}

	/* Clock gating */
	{
		/* GVD */
		{
			uint8_t duty;
			float rate = 50.0f; /* 0.0 to 100.0 [%] */
			if(rate <= 0.0f) duty = 0x00;
			else if(rate >= 100.0f) duty = 0x80;
			else duty = (uint8_t)(rate*1.28f);
			MTX_Printf("[Clock] GVD clock duty rate : %.2f%% (0x%02X)\n", rate, duty);
			AG903_SSCPrmSetGvdClkDuty(duty);
		}

		/* GFX */
		{
			uint8_t duty;
			float rate = 100.0f; /* 0.0 to 100.0 [%] */
			if(rate <= 0.0f) duty = 0.0f;
			else if(rate >= 100.0f) duty = 0x80;
			else duty = (uint8_t)(rate*1.28f);
			MTX_Printf("[Clock] GFX clock duty rate : %.2f%% (0x%02X)\n", rate, duty);
			AG903_SSCPrmSetGfxClkDuty(true, duty);
		}
	}

	/* GVD */
	{
		int32_t err;
		err = movie_init();
		if(err) return err;
	}

	ERRCHK(AG903_ENONE, AG903_BMUMgrGetHandle(&MTX_bmu_handle[0]));
	ERRCHK(AG903_ENONE, AG903_BMUMgrGetHandle(&MTX_bmu_handle[1]));

	ERRCHK(AG903_ENONE, MTX_setupDisplay());

	/* OSPMgr */
	{
		ERRCHK(AG903_ENONE, AG903_OSPMgrInit());
		ERRCHK(AG903_ENONE, AG903_OSPMgrGetHandle(&MTX_osp_handle));
		gOSPBufferAddr = sys_malloc(5*4 + 32);
		AG903_OSPCmdBuf cmdbuf;
		cmdbuf.addr = gOSPBufferAddr;
		cmdbuf.size = (5*4 + 32);
		cmdbuf.mode = AG903_OSP_BUFMODE_FIFO;
		ERRCHK(AG903_ENONE, AG903_OSPMgrSetCommandBuf(MTX_osp_handle, &cmdbuf, true));
		ERRCHK(AG903_ENONE, AG903_OSPMgrSetCommand(MTX_osp_handle, AG903_OSP_CMD_EVNT_WAIT, AG903_EVENT40_DSP0));
		ERRCHK(AG903_ENONE, AG903_OSPMgrSetCommand(MTX_osp_handle, AG903_OSP_CMD_BUS_BURST_FIX, 2));
		ERRCHK(AG903_ENONE, AG903_OSPMgrSetCommand(MTX_osp_handle, AG903_OSP_CMD_BUS_ADDR, AG903_SSC_BASE+0x154));
		ERRCHK(AG903_ENONE, AG903_OSPMgrSetCommand(MTX_osp_handle, AG903_OSP_CMD_BUS_DATA, 1<<0));
		ERRCHK(AG903_ENONE, AG903_OSPMgrSetCommand(MTX_osp_handle, AG903_OSP_CMD_BUS_DATA, 1<<4));
	}

	/* Timer */
	{
		ERRCHK(AG903_ENONE, AG903_TIMRMgrInit());

		/* TimerMgr init */
		ERRCHK(AG903_ENONE, AG903_TIMRMgrGetHandle(&MTX_tim_handle));
		ERRCHK(AG903_ENONE, AG903_TIMRMgrSetIntHandler(MTX_tim_handle, (void *)(TimerHandler), MTX_tim_handle));
		ERRCHK(AG903_ENONE, AG903_TIMRMgrEnableIntMask(MTX_tim_handle, AG903_TIMR_COMPARE_BIT));
		ERRCHK(AG903_ENONE, AG903_TIMRMgrDisableIntMask(MTX_tim_handle, AG903_TIMR_OVERFLOW_BIT));
		ERRCHK(AG903_ENONE, AG903_TIMRMgrSetCount(MTX_tim_handle, 0));

		mpsContext *mpsctx = MPS_getContext(0);

		AG903_TIMRMgrTickCntParam param = {
			.match = 0,
			.resolution = AG903_TIMR_CNT_SYSCLK,
			.oneshot = false,
			.output = NULL,
		};
		if(mpsctx->info.time_scale != 0)
		{
			param.period = (uint32_t)(AG903_SAMPLE_SYSCLK *
									  ((float)mpsctx->info.frame_length / mpsctx->info.time_scale));
		}
		else
		{
			param.period = (uint32_t)(AG903_SAMPLE_SYSCLK * ((float)1 / 30));
		}
		ERRCHK(AG903_ENONE, AG903_TIMRMgrSetTickCountMode(MTX_tim_handle, &param));
		ERRCHK(AG903_ENONE, AG903_TIMRMgrStart(MTX_tim_handle)); /* タイマモジュールをキック */
	}

	MTX_Printf("<<< Setting done.\n");

	/* 再生処理開始 */
	gMovieTaskID = acre_tsk((T_CTSK*)&ctsk_movie);

	/* 描画処理開始 */
	gGFXTaskID = acre_tsk((T_CTSK*)&ctsk_gfx);

	/* INT */
	{
		AG903_INTMgrHdrPrm hdrprm;
		hdrprm.atr		= AG903_INT_HLNG;
		hdrprm.func		= (void *)(DisplayHandler);
		hdrprm.intno	= AG903_IRQ16_DSP0;
		gID_IRQ_DSP		= AG903_INTMgrSetHandler(&hdrprm);
		ERRCHK(AG903_ENONE, AG903_INTMgrEnableInt(AG903_IRQ16_DSP0));
	}

	sys_dlytsk(100); /* 他タスク初期化猶予 */

	/* メイン処理中 */
	{
		char input[2];
		MTX_Printf("Press enter key to exit.\r\n");
		COM_GetNum_Wait(input, sizeof(input));
		gFlagExit = true;
	}

	while(!gFlagMPSDone)		{ sys_dlytsk(100); }; /* 動画終了処理待ち */
	while(gID_MPL_GFX != 0)	{ sys_dlytsk(10);  }; /* 描画終了処理待ち */

	sys_dlytsk(100); /* 他タスク終了猶予 */

	/* 終了処理 */
	{
		if(gAsyncTaskID >= 0) {
			ERRCHK(E_OK, del_tsk(gAsyncTaskID));
			gAsyncTaskID = -1;
		}
		if(gMovieTaskID >= 0) {
			ERRCHK(E_OK, del_tsk(gMovieTaskID));
			gMovieTaskID = -1;
		}
		if(gGFXTaskID >= 0) {
			ERRCHK(E_OK, del_tsk(gGFXTaskID));
			gGFXTaskID = -1;
		}

		ERRCHK(AG903_ENONE, AG903_INTMgrDisableInt(AG903_IRQ16_DSP0));
		ERRCHK(AG903_ENONE, AG903_INTMgrDeleteHandler(gID_IRQ_DSP));

		ERRCHK(AG903_ENONE, AG903_OSPMgrClearCommand(MTX_osp_handle));
		ERRCHK(AG903_ENONE, AG903_OSPMgrClearFIFO(MTX_osp_handle));
		ERRCHK(AG903_ENONE, AG903_OSPMgrReleaseHandle(MTX_osp_handle));
		ERRCHK(AG903_ENONE, sys_free(gOSPBufferAddr));
		gOSPBufferAddr = NULL;

		ERRCHK(AG903_ENONE, AG903_TIMRMgrStop(MTX_tim_handle));
		ERRCHK(AG903_ENONE, AG903_TIMRMgrDeleteIntHandler(MTX_tim_handle, (void *)(TimerHandler)));

		ERRCHK(AG903_ENONE, MPS_Finalize());
		mpsconf = MPS_getConfig();
		ERRCHK(AG903_ENONE, sys_free(mpsconf->memory_heap_top));
		mpsconf->memory_heap_top = NULL;
		ERRCHK(AG903_ENONE, sys_free(mpsconf->memory_work_top));
		mpsconf->memory_work_top = NULL;

		ERRCHK(AG903_ENONE, umountp(0, (ID)Fsif_GetDevid(FSIF_DEV_CF))); /* CFアンマウント */

		ERRCHK(AG903_ENONE, AG903_DSPMgrDisable(MTX_dsp_handle));
		while(AG903_DSPMgrCheckStopped(MTX_dsp_handle));
		AG903_DSPMgrIntStat intclr = {
			.clr_dspoff		= true,
			.clr_hrz_line	= true,
			.clr_vt_blank	= true,
		};
		AG903_DSPMgrClearIntStat(MTX_dsp_handle, &intclr);
		ERRCHK(AG903_ENONE, AG903_DSPMgrReleaseHandle(MTX_dsp_handle));
		ERRCHK(AG903_ENONE, sys_free(gWindowAttributeAddr));
		gWindowAttributeAddr = NULL;

		ERRCHK(AG903_ENONE, AG903_BMUMgrDisable(MTX_bmu_handle[0]));
		ERRCHK(AG903_ENONE, AG903_BMUMgrReleaseHandle(MTX_bmu_handle[0]));
	}

	MTX_Printf("Main task done.\n");
	MTX_Printf("\n[SAMPLE END]\n");

	return AG903_ENONE;
}

static void TimerHandler(AG903_TIMRMgrHandle *handle)
{
	AG903_TIMRMgrClearStatus(handle, 1<<1 | 1<<0);
	WindowUpdate();
}

static void DisplayHandler(void)
{
	AG903_DSPMgrIntStat int_stat;
	int_stat.clr_vt_blank = true;
	int_stat.clr_dspoff = true;
	int_stat.clr_hrz_line = true;
	AG903_DSPMgrClearIntStat(MTX_dsp_handle, &int_stat);
	wup_tsk(gGFXTaskID);
}

static int32_t MTX_setupDisplay(void)
{
	mpsContext *mpsctx;
	gWindowAttributeAddr = sys_memalign(0x20, 0x10);
	if(gWindowAttributeAddr == NULL)
	{
		MTX_ErrPrintf("ERROR: Out of memory.\n");
		return -AG903_ENOMEM;
	}

	AG903_DSPMgrCtrlParam		dsp_ctrl		= {0};
	AG903_DSPMgrCMOSParam		dsp_cmos		= {0};
	AG903_DSPMgrWinAttribute	*dsp_attr		= NULL;
	AG903_DSPMgrWindowParam		dsp_win			= {0};
	AG903_DSPMgrIntParam		dsp_int			= {0};

	ERRCHK(AG903_ENONE, AG903_DSPMgrInit());

	MTX_Printf("Initialize display settings...\n");

	ERRCHK(AG903_ENONE, AG903_DSPMgrGetHandle(0, &MTX_dsp_handle));

	/* PORT */
	AG903_DSPMgrSetPortSel(MTX_dsp_handle, AG903_VOD0_PORTSEL_LVCMOS24);

	dsp_ctrl.ip_sel = AG903_DSP_VMODE_NONINTERLACE;
	dsp_ctrl.hrz_framesize = 1280;
	dsp_ctrl.vt_framesize  = 1024;
	dsp_ctrl.syncparam = &DSP_SAMPLE_SYNCPARAM[DSP_SAMPLE_RES_SXGA];

	/* PLL */
	AG903_SPCPrmPllnParam pll = {0};
	AG903_SPCPrmSetPll1Ctrl(&pll);
	sys_delayus(50); /* PLL待ち */
	AG903_SPCPrmSetPll1Ctrl(&DSP_SAMPLE_PLL[DSP_SAMPLE_RES_SXGA]);
	sys_delayus(50); /* PLLロックアップ待ち */

	/* 表示端子方向設定 */
	AG903_SSCPrmDspSetup dsp_setup;
	AG903_SSCPrmGetDspPinDir(&dsp_setup);
	dsp_setup.dot0		= AG903_SSC_PINDIR_OUTPUT;
	dsp_setup.dot1		= AG903_SSC_PINDIR_OUTPUT;
	dsp_setup.field0	= AG903_SSC_PINDIR_OUTPUT;
	dsp_setup.field1	= AG903_SSC_PINDIR_OUTPUT;
	dsp_setup.vsync0	= AG903_SSC_PINDIR_OUTPUT;
	dsp_setup.vsync1	= AG903_SSC_PINDIR_OUTPUT;
	AG903_SSCPrmSetDspPinDir(&dsp_setup);

	dsp_cmos.dotclk_polarity = AG903_VOD_DOTCLK_LATCH_FALL;
	dsp_cmos.field_polarity  = AG903_DSP_POLARITY_POSI;
	dsp_cmos.hsync_polarity  = AG903_DSP_POLARITY_NEGA;
	dsp_cmos.vsync_polarity  = AG903_DSP_POLARITY_NEGA;
	dsp_cmos.rgbde_polarity  = AG903_DSP_POLARITY_POSI;
	dsp_cmos.hsync_en        = true;
	dsp_cmos.vsync_en        = true;
	dsp_cmos.rgbde_en        = true;
	dsp_cmos.pixeldata_en    = true;

	ERRCHK(AG903_ENONE,
		   AG903_DSPMgrSetCMOSParam(MTX_dsp_handle, &dsp_ctrl, &dsp_cmos));


	/* VSYNC EVENT OUTPUT ENABLE */
	dsp_int.trigger_out		= AG903_DSP_EVENT_VT;
	dsp_int.trigger_vt		= AG903_DSP_TRG_VT_START_OF_VBLANK;
	dsp_int.int_vt_blank		= AG903_DSP_INT_START_OF_VBLANK;
	dsp_int.mask_vt_blank	= false;
	dsp_int.mask_dspoff		= true;
	dsp_int.mask_error		= true;
	dsp_int.mask_hrz_line	= true;
	AG903_DSPMgrSetIntParam(MTX_dsp_handle, &dsp_int);


	dsp_win.update_timing	= AG903_DSP_ATTR_END_OF_VSYNC;
	dsp_win.background		= 0x00000000;
	dsp_win.num_config		= 1;
	dsp_win.num_attr			= 1;
	dsp_win.palette_update	= 0;
	dsp_win.window_attr_base	= (uint32_t)gWindowAttributeAddr;
	dsp_win.window_attr_update = 1;
	ERRCHK(AG903_ENONE,
		   AG903_DSPMgrSetWindowParam(MTX_dsp_handle, &dsp_win));

	/* Window 0 */
	mpsctx = MPS_getContext(0);
	ERRCHK(AG903_ENONE, AG903_DSPMgrGetAttribute(MTX_dsp_handle, 0, &dsp_attr));
	sys_memset(dsp_attr, 0, 0x20);
	dsp_attr[0].position_x			= (dsp_ctrl.hrz_framesize - MTX_GFX_CANBUS_WIDTH)>>1;
	dsp_attr[0].position_y			= (dsp_ctrl.vt_framesize - MTX_GFX_CANBUS_HEIGHT)>>1;
	dsp_attr[0].destination_width	= MTX_GFX_CANBUS_WIDTH;
	dsp_attr[0].destination_height	= MTX_GFX_CANBUS_HEIGHT;
	dsp_attr[0].source_width		= MTX_GFX_CANBUS_WIDTH;
	dsp_attr[0].source_height		= MTX_GFX_CANBUS_HEIGHT;

	dsp_attr[0].framebuffer_base = 0x00000000;

	dsp_attr[0].hrz_size = dsp_attr[0].source_width * 3;
	dsp_attr[0].conf.default_alpha = 0xFF;
	dsp_attr[0].conf.framebuffer_format = AG903_DSP_FFMT_R8G8B8;
	dsp_attr[0].conf.valid = false;

	ERRCHK(AG903_ENONE, AG903_DSPMgrSetAttribute(MTX_dsp_handle, 0));

	/* 出力先にBMUを指定 */
	{
		mpsConfig *mpsconf = MPS_getConfig();
		int32_t bmuid;
		uint32_t addr, paddr, fbase, stride;
		uint8_t bmusrc = AG903_BMU_SRC_GVD0;
		AG903_DSPMgrWinAttribute *attr;

		ERRCHK(GVD_OUTMOD_BMU, mpsconf->output_select);

		ERRCHK(AG903_ENONE, AG903_BMUMgrSetMode(MTX_bmu_handle[0],
												AG903_BMU_SINK_WAIT_DISABLE,
												AG903_BMU_BUF_MGR_MODE1));
		mpsctx = MPS_getContext(0);
		ERRCHK(AG903_ENONE, GVD_GetBMUId(mpsctx->gvdctx, &bmuid));
		switch (bmuid)
		{
		case 0:
			bmusrc = AG903_BMU_SRC_GVD0;
			break;
		case 1:
			bmusrc = AG903_BMU_SRC_GVD1;
			break;
		case 2:
			bmusrc = AG903_BMU_SRC_GVD2;
			break;
		case 3:
			bmusrc = AG903_BMU_SRC_GVD3;
			break;
		}
		ERRCHK(AG903_ENONE, AG903_BMUMgrSetSrcModule(MTX_bmu_handle[0], bmusrc));
		ERRCHK(AG903_ENONE, AG903_BMUMgrAddSinkModule(MTX_bmu_handle[0], AG903_BMU_SINK_SYS0));
		ERRCHK(AG903_ENONE, AG903_BMUMgrAddSinkModule(MTX_bmu_handle[0], AG903_BMU_SINK_DSP0));
		stride = gOutbufinfo[0].size_buffer/MTX_MOV_OUTBUF_COUNT;
		paddr = (uint32_t)gOutbufinfo[0].buffer;
		ERRCHK(AG903_ENONE, AG903_BMUMgrSetBufferConfig(MTX_bmu_handle[0], (void *)paddr,
														stride, MTX_MOV_OUTBUF_COUNT));
		ERRCHK(AG903_ENONE, AG903_BMUMgrGetBMUSinkAddress(MTX_bmu_handle[0], &fbase));

		ERRCHK(AG903_ENONE, AG903_DSPMgrGetAttribute(MTX_dsp_handle, 0, &attr));
		attr[0].framebuffer_base = fbase;
		ERRCHK(AG903_ENONE, AG903_DSPMgrSetAttribute(MTX_dsp_handle, 0));

		ERRCHK(AG903_ENONE, AG903_BMUMgrGetBMUSrcAddress(MTX_bmu_handle[0], &addr));
		ERRCHK(AG903_ENONE, GVD_SetBMUAddr(mpsctx->gvdctx, (void *)addr));
		ERRCHK(AG903_ENONE, AG903_BMUMgrEnable(MTX_bmu_handle[0]));
	}

	/* バックライト制御 OFF */
	Board_BacklightSel(0, 0);
	Board_BacklightSel(1, 0);

	/* 表示ON */
	ERRCHK(AG903_ENONE, AG903_DSPMgrEnable(MTX_dsp_handle));

	/* CMOS出力有効 */
	Board_SelectDviTX();

	sys_dlytsk(1000); /* ディスプレイの安定待ち */

	return AG903_ENONE;
}

void movie_tsk(VP_INT exinf)
{
	((void)exinf);

	movie_play();

	MTX_Printf("Movie task done.\n");
	ext_tsk();
}

void gfx_tsk(VP_INT exinf)
{
	((void)exinf);
	int32_t rc = AG903_ENONE;

	rc = gfx_init();

	if (rc == AG903_ENONE) {
		while(!gFlagExit) {
			gfx_run();
			slp_tsk();
		};
	}

	gfx_final();

	MTX_Printf("GFX task done.\n");
	ext_tsk();
}
