#include "sample_common.h"
#include "com.h"
#include "cap_simple.h"
#include "cap_common.h"

#include "via/viamgr.h"
#include "pgp/pgpmgr.h"
#include "dsp/dspmgr.h"

extern int32_t gCAPErrCode;		/* エラーチェック用 */

int32_t CAP_Simple_Demo(uint32_t mode)
{
	int32_t rc = AG903_ENONE;

	int32_t				pipe_num		= -1;
	CAP_Framebuffer		framebuffer		= {0};
	AG903_DSPMgrWindowParam win_param	= {0};
	uint32_t			status;
	uint32_t			loop;

	AG903_ViaMgrInputHandle		*via	= NULL;
	AG903_VidMgrOutputHandle	*vid	= NULL;
	AG903_DSPMgrHandle			*dsp	= NULL;
	AG903_DSPMgrWinAttribute	*attr	= NULL;

	if (mode >= CAP_MODE_MAX) {
		CAP_ErrPrintf("ERROR: INVALID MODE. ABORT.\r\n");
		return -AG903_EINVAL;
	}

	/* フレームバッファ確保 */
	if(CAP_MODE_VIA_LVDS == mode || CAP_MODE_VIA_CMOS == mode) {
		via = CAP_GetVIAHandle(0);
		framebuffer.size = CAP_ANALOG_IN_WIDTH*CAP_ANALOG_IN_HEIGHT*2;
	}
	else {
		vid = CAP_GetVIDOutHandle();
		framebuffer.size = CAP_DIGITAL_IN_WIDTH*CAP_DIGITAL_IN_HEIGHT*4;
	}
	framebuffer.buf = sys_memalign(framebuffer.size, 0x1000);
	if (framebuffer.buf == NULL) {
		CAP_ErrPrintf("ERROR: Framebuffer allocate failed.\r\n");
		rc = -AG903_ENOMEM;
		return rc;
	}
	sys_memset(framebuffer.buf, 0, framebuffer.size);

	/* 表示共通設定 */
	rc = CAP_SetupDisplay(mode);
	if (CAP_MODE_VIA_LVDS == mode || CAP_MODE_VID == mode) {
		dsp = CAP_GetDSPHandle(1);
	} else {
		dsp = CAP_GetDSPHandle(0);
	}

	/* ウィンドウ0 */
	AG903_DSPMgrGetAttribute(dsp, 0, &attr);
	sys_memset(attr, 0, 0x20);
	attr->destination_width  = CAP_WINDOW_WIDTH;
	attr->position_x = (CAP_DISPLAY_WIDTH - CAP_WINDOW_WIDTH)>>1; /* センタリング */
	attr->destination_height = CAP_WINDOW_HEIGHT;
	attr->position_y = (CAP_DISPLAY_HEIGHT - CAP_WINDOW_HEIGHT)>>1; /* センタリング */
	attr->framebuffer_base = (uint32_t)framebuffer.buf;
	attr->conf.default_alpha = 0xFF;
	attr->conf.valid = true;
	if(CAP_MODE_VIA_LVDS == mode || CAP_MODE_VIA_CMOS == mode) {
		attr->source_width  = CAP_ANALOG_IN_WIDTH;
		attr->source_height = CAP_ANALOG_IN_HEIGHT;
		attr->hrz_size      = attr->source_width<<1;
		attr->conf.framebuffer_format = AG903_DSP_FFMT_YUV422_BT601_LIMIT;
	}
	else {
	    attr->source_height = CAP_DIGITAL_IN_HEIGHT;
	    attr->source_width  = CAP_DIGITAL_IN_WIDTH;
	    attr->hrz_size      = attr->source_width<<2;
	    attr->conf.framebuffer_format = AG903_DSP_FFMT_X8R8G8B8;
	}
	NOERRCHK(AG903_ENONE, AG903_DSPMgrSetAttribute(dsp, 0));

	/* ウィンドウ設定 */
	win_param.background			= 0xFF000000;
	win_param.num_attr				= 1;
	win_param.num_config			= 1;
	win_param.update_timing			= AG903_DSP_ATTR_END_OF_VSYNC;
	win_param.window_attr_base		= (uint32_t)attr;
	win_param.window_attr_update	= true;
	NOERRCHK(AG903_ENONE, AG903_DSPMgrSetWindowParam(dsp, &win_param));

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

	/* PGP設定 */
	AG903_PgpMgrPipelineHandle *pgp;
	rc = AG903_PgpMgrGetPipelineHandle(1, &pgp);

	if(CAP_MODE_VIA_LVDS == mode || CAP_MODE_VIA_CMOS == mode) {
		/*--- パイプラインの設定:入力段 ---*/
		/* 入力ポート:VIAから入力 */
		NOERRCHK(AG903_ENONE, AG903_PgpMgrSetInputPort(pgp, via));
		/* 入力動作モード：ODDフィールドのVSYNCを基準にする */
		NOERRCHK(AG903_ENONE, AG903_PgpMgrSetParamInputMode(pgp, AG903_PGP_MGR_INPUT_MD_ODD_VSYNC));
		/* HSYNC入力ディレイ:遅延無し */
		NOERRCHK(AG903_ENONE, AG903_PgpMgrSetParamInputHSyncDelay(pgp, CAP_HSYNC_DELAY));
		/* 入力フレーム走査方法:インタレース, VPOS調整なし */
		NOERRCHK(AG903_ENONE, AG903_PgpMgrSetParamInputScan(pgp, AG903_PGP_MGR_SCAN_INTERLACE, false, false));
		/* 入力フォーマット:YCbCr422 IP変換有効 */
		NOERRCHK(AG903_ENONE, AG903_PgpMgrSetParamInputFormat(pgp, AG903_PGP_MGR_INPUT_FMT_YCBCR422_W_IP));
		/* IP変換回路設定:Limited range, ブランク中は0x00を出力 */
		NOERRCHK(AG903_ENONE, AG903_PgpMgrSetConfigIPConversion(pgp, AG903_PGP_MGR_LIMIT_16_235_AND_240, 0x00, 0x00));
		/* 入力解像度設定 */
		NOERRCHK(AG903_ENONE, AG903_PgpMgrSetParamInputSize(pgp, CAP_ANALOG_IN_HEIGHT>>1, CAP_ANALOG_IN_WIDTH));
		/* キャプチャ開始座標指定 */
		NOERRCHK(AG903_ENONE, AG903_PgpMgrSetParamInputPosition(pgp, CAP_VIA_VPOS_OFFSET, CAP_VIA_HPOS_OFFSET));

		/*--- パイプラインの設定:出力段 ---*/
		/* 出力フォーマット:YCbCr422 */
		NOERRCHK(AG903_ENONE, AG903_PgpMgrSetParamOutputFormat(pgp, AG903_PGP_MGR_OUTPUT_FMT_YCBCR444_TO_YCBCR422));
		/* 出力アドレス指定 */
		NOERRCHK(AG903_ENONE, AG903_PgpMgrSetConfigOutputBaseAddr(pgp, framebuffer.buf));
		/* 出力アドレス指定方法:2次元 */
		NOERRCHK(AG903_ENONE, AG903_PgpMgrSetParamOutputAddrDim(pgp, AG903_PGP_MGR_ADDR_DIMENTION_2));
		/* 2次元出力時のストライド指定 */
		NOERRCHK(AG903_ENONE, AG903_PgpMgrSetParamOutputStride(pgp, CAP_ANALOG_IN_WIDTH << 1));
		/* 出力フレーム走査方法:プログレッシブ */
		NOERRCHK(AG903_ENONE, AG903_PgpMgrSetParamOutputScan(pgp, AG903_PGP_MGR_SCAN_PROGRESSIVE));
		/* インタレース入力のフレーム保存方法:フィールドに従う */
		NOERRCHK(AG903_ENONE, AG903_PgpMgrSetConfigOutputInterlaceFrame(pgp, AG903_PGP_MGR_OUTPUT_FRAME_SAVE_FIELD));
		/* 出力リミッタ設定:リミッタ有効(16-235/0-240) */
		NOERRCHK(AG903_ENONE, AG903_PgpMgrSetConfigOutputLimit(pgp, AG903_PGP_MGR_LIMIT_16_235_AND_240));
	}
	else {
		/*--- パイプラインの設定:入力段 ---*/
		/* 入力ポート:VIDから入力 */
		NOERRCHK(AG903_ENONE, AG903_PgpMgrSetInputPort(pgp, vid));
		/* 入力動作モード：キャプチャ開始・終了をVSYNCを基準 */
		NOERRCHK(AG903_ENONE, AG903_PgpMgrSetParamInputMode(pgp, AG903_PGP_MGR_INPUT_MD_VSYNC));
		/* HSYNC入力ディレイ:遅延無し */
		NOERRCHK(AG903_ENONE, AG903_PgpMgrSetParamInputHSyncDelay(pgp, CAP_HSYNC_DELAY));
		/* 入力フォーマット:RGB888 */
		NOERRCHK(AG903_ENONE, AG903_PgpMgrSetParamInputFormat(pgp, AG903_PGP_MGR_INPUT_FMT_RGB888));
		/* 入力解像度設定 */
		NOERRCHK(AG903_ENONE, AG903_PgpMgrSetParamInputSize(pgp, CAP_DIGITAL_IN_HEIGHT, CAP_DIGITAL_IN_WIDTH));
		/* キャプチャ開始座標指定 */
		NOERRCHK(AG903_ENONE, AG903_PgpMgrSetParamInputPosition(pgp, CAP_VID_VPOS_OFFSET, CAP_VID_HPOS_OFFSET));

		/*--- パイプラインの設定:出力段 ---*/
		/* 出力フォーマット:RGB888 */
		NOERRCHK(AG903_ENONE, AG903_PgpMgrSetParamOutputFormat(pgp, AG903_PGP_MGR_OUTPUT_FMT_RGB888_TO_RGB888_32BIT));
		/* 出力アドレス指定 */
		NOERRCHK(AG903_ENONE, AG903_PgpMgrSetConfigOutputBaseAddr(pgp, framebuffer.buf));
		/* 出力アドレス指定方法:2次元 */
		NOERRCHK(AG903_ENONE, AG903_PgpMgrSetParamOutputAddrDim(pgp, AG903_PGP_MGR_ADDR_DIMENTION_2));
		/* 2次元出力時のストライド指定 */
		NOERRCHK(AG903_ENONE, AG903_PgpMgrSetParamOutputStride(pgp, CAP_DIGITAL_IN_WIDTH<<2));
		/* 出力リミッタ設定:リミッタ有効(0-255) */
		NOERRCHK(AG903_ENONE, AG903_PgpMgrSetConfigOutputLimit(pgp, AG903_PGP_MGR_LIMIT_0_255));
		/* フレーム保存時のパディング：0xFF */
		NOERRCHK(AG903_ENONE, AG903_PgpMgrSetConfigOutputFramePadding(pgp, 0xFF));
	}

	/* パイプライン割り当て */
	pipe_num = AG903_PgpMgrAssignPipeline(pgp);
	CAP_Printf("[PGP] Pipeline #%u assigned.\r\n", pipe_num);

	/* キャプチャ開始 */
	NOERRCHK(AG903_ENONE, AG903_PgpMgrExecPipeline(pgp, AG903_PGP_MGR_CMD_EXEC_CONTINUE));

	{
		char input[2];
		CAP_Printf("Press enter key to exit.");
		COM_GetNum_Wait(input, sizeof(input));
	}

	/* キャプチャ停止 */
	NOERRCHK(AG903_ENONE, AG903_PgpMgrExecPipeline(pgp, AG903_PGP_MGR_CMD_IDLE));

	/* パイプライン停止待ち */
	for(loop=0; loop<CAP_PIPESTOP_TIMEOUT; loop++) {
		NOERRCHK(AG903_ENONE, AG903_PgpMgrGetPipelineStatus(pgp, NULL, NULL, NULL, NULL, &status));
		if(AG903_PGP_MGR_STATE_IDLE == status) {
			break;
		}
		sys_dlytsk(10);
	}
	if(CAP_PIPESTOP_TIMEOUT<=loop) {
		CAP_ErrPrintf("ERROR: Pipeline Stop Failure.\r\n");
	}

	/* パイプラインハンドラ返却 */
	NOERRCHK(AG903_ENONE, AG903_PgpMgrReleasePipelineHandle(pgp));

	/* 終了処理 */
	sys_free(framebuffer.buf); /* フレームバッファ解放 */
	rc = CAP_ReleaseDisplay(); /* 表示終了処理 */

	return rc;
}

