/***************************************************************************
 *
 * CRI Middleware SDK
 *
 * Copyright (c) 2001-2004 CRI-MW
 *
 * Appli.   : ADXT Sample Program 
 * Module   : Main function.(ADX File system - Asynchronous reading)
 * File     : adxrdnw.c
 *
 ***************************************************************************/

/***************************************************************************
 *		インクルードファイル
 *		Include file
 ***************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <cri_mw.h>

#include "usr/usr.h"
#include "data.h"

/***************************************************************************
 *		定数マクロ
 *		Constant Macro
 ***************************************************************************/
/*	パーティションＩＤ	*/
/*	Partition ID		*/
#define	PATID			(0)

/*	パーティション内の最大ファイル数			*/
/*	The number of maximum files in partition	*/
#define	MAX_NFILES		(5)

/*	最大ADXFハンドル数						*/
/*	The number of maximum ADXF handles		*/
#define	MAX_ADXF		(5)

/*	最大チャンネル数				*/
/*	The number of maximum channels	*/
#define	MAX_CH			(2)

/*	同時再生最大ストリーム数									*/
/*	The number of maximum disc streams playing at the same time	*/
#define	MAX_STM			(1)

/*	最高サンプリング周波数		*/
/*	Maximum sampling frequency	*/
#define	MAX_SFREQ		(48000)

/*	ファイル再生用ワーク領域の大きさ	*/
/*	Work area size of disc stream play	*/
#define WKSIZE			ADXT_CALC_WORK(MAX_CH, 1, MAX_STM, MAX_SFREQ)

/*	ファイル読み込み用ワーク領域の大きさ	*/
/*	Work area size of reading data			*/
#define	PTINFOSIZE		(ADXF_CALC_PTINFO_SIZE(MAX_NFILES))

/***************************************************************************
 *		処理マクロ
 *		Process MACRO
 ***************************************************************************/
/*	フラグON/OFFの反転		*/
/*	Turn over flag(ON/OFF)	*/
#define NOT_FLAG(flag)		(((flag) == OFF) ? ON : OFF)

#define UNUSED(val)			((val) = (val))

/***************************************************************************
 *		変数定義
 *		Variable Definition
 ***************************************************************************/
/*	アプリケーション構造体											*/
/*	Application structure											*/
typedef struct {
	Sint32	disp_flag;			//	Display information flag
	char	*afsfname;				//	AFS file name
	char	*adxfname;				//	ADX file name
	ADXF	adxf[MAX_ADXF];			//	ADXF handle
	ADXT	adxt;					//	ADXT handle
	Uint8	ptinfo[PTINFOSIZE];		//	Partition infomation area
	Uint8	work[WKSIZE];			//	Work area
	Uint8	*data_buf;				//	Data buffer
	Uint8	*malloc_adr;			//	malloc address
} AP_OBJ;

/*	アプリケーションオブジェクト									*/
/*	Application Object												*/
AP_OBJ ap_obj = {
	ON,							//	Sint32	disp_flag;
	"data.afs",					//	AFS file name
	"bgmlp48a.adx",				//	ADX file name
};

/***************************************************************************
 *		関数宣言
 *		Function Declaration
 ***************************************************************************/
void ap_adx_err_func(void *obj, Char8 *msg);
void ap_disp_info(AP_OBJ *ap);
void ap_clear_data(AP_OBJ *ap);
void ApInitMw(AP_OBJ *ap);
void ApFinishMw(AP_OBJ *ap);
void ApStart(AP_OBJ *ap);
void ApStop(AP_OBJ *ap);
Sint32 ApExec(AP_OBJ *ap);

/***************************************************************************
 *		関数定義
 *		Function Definition
 ***************************************************************************/

/*	ADXTエラー発生時に起動する関数					*/
/*	Callback function when an error occur in ADXT	*/
void ap_adx_err_func(void *obj, Char8 *msg)
{
	UNUSED(obj);		// 未使用変数

	UsrDbgPrintf(msg);

	for (;;) {		/*	リリース時には無くす					*/
		;			/*	Delete when you release application.	*/
	}
}

/*	ミドルウェアの初期化				*/
/*	Initialize Middleware				*/
void ApInitMw(AP_OBJ *ap)
{
	UNUSED(ap);	// 未使用変数

	/*	ADXライブラリ初期化		*/
	/*	Initialize ADX library	*/
	ADXT_Init();
}

/*	ミドルウェアの終了					*/
/*	Finalize Middleware					*/
void ApFinishMw(AP_OBJ *ap)
{
	UNUSED(ap);	// 未使用変数

	ADXT_Finish();
}

/*	データ領域のクリア	*/
/*	Clear data area		*/
void ap_clear_data(AP_OBJ *ap)
{
	memset(ap->data_buf, 'x', 100*2048);
}

/*	アプリケーション開始処理	*/
/*	Start application			*/
void ApStart(AP_OBJ *ap)
{
	/*	パーティション情報の読み込み	*/
	/*	Load partition infomation		*/
	memset(ap->ptinfo, 0, sizeof(ap->ptinfo));
	ADXF_LoadPartitionNw(PATID, ap->afsfname, NULL, ap->ptinfo);
	for (;;) {
		if (ADXF_GetPtStat(PATID) == ADXF_STAT_READEND) {
			break;
		}
		ADXM_ExecMain();
		ADXM_WaitVsync();
	}
	/*	データ読み込み領域の確保			*/
	/*	Allocate buffer for reading data	*/
	ap->malloc_adr = UsrMalloc(100*2048 + 63);

	ap->data_buf = (Uint8 *)(((UintPtr)(ap->malloc_adr) + 63) & 0xffffffc0);
	ap_clear_data(ap);

	/*	AFSファイルのオープン	*/
	/*	Open AFS file			*/
	if ((ap->adxf[0]=ADXF_OpenAfs(PATID, TEST1_BIN)) == NULL) {
		for (;;) ;
	}
	if ((ap->adxf[1]=ADXF_OpenAfs(PATID, TEST2_BIN)) == NULL) {
		for (;;) ;
	}
	if ((ap->adxf[2]=ADXF_OpenAfs(PATID, TEST3_BIN)) == NULL) {
		for (;;) ;
	}
	if ((ap->adxf[3]=ADXF_OpenAfs(PATID, TEST4_BIN)) == NULL) {
		for (;;) ;
	}
	if ((ap->adxf[4]=ADXF_OpenAfs(PATID, TEST5_BIN)) == NULL) {
		for (;;) ;
	}

	/*	ADXファイル再生用ハンドルの生成		*/
	/*	Create ADXT handle					*/
	if ((ap->adxt=ADXT_Create(2, ap->work, WKSIZE)) == NULL) {
		for (;;) ;
	}
	/*	再生開始		*/
	/*	Start to play	*/
	ADXT_StartFname(ap->adxt, ap->adxfname);

}

/*	アプリケーション停止処理	*/
/*	Stop application			*/
void ApStop(AP_OBJ *ap)
{
	Sint32	i;

	/*	ADXT ハンドルの消去	*/
	/*	Destroy ADXT handle	*/
	ADXT_Destroy(ap->adxt);
	ap->adxt = NULL;

	/*	AFSファイルのクローズ	*/
	/*	Close AFS file			*/
	for (i = 0; i < MAX_ADXF; i++) {
		ADXF_Close(ap->adxf[i]);
		ap->adxf[i] = NULL;
	}

	UsrFree(ap->malloc_adr);
	ap->malloc_adr	= NULL;
	ap->data_buf	= NULL;

}

/*	情報の表示			*/
/*	Display infomation	*/
void ap_disp_info(AP_OBJ *ap)
{
	Sint32	i, j;
	char 	*ststr[5] = {"    ", "STOP", "READ", "END ", "ERR "};

	UsrPrintf(3, 3, "ADXF Sample Program");
	UsrPrintf(3, 4, "   (Reading data with playing ADX)");

	for (i = 0; i < 12; i++) {
		for (j = 0; j < 32; j++)
			UsrPrintf(3 + j, 6 + i, "%c", ap->data_buf[i*2048*5+j]);
	}

	for (i = 0; i < MAX_ADXF; i++) {
		UsrPrintf(40, 6 + i, "%s", ststr[ADXF_GetStat(ap->adxf[i])]);
	}
}

/*	アプリケーションメイン処理	*/
/*	Run application				*/
Sint32 ApExec(AP_OBJ *ap)
{
	const USR_PERIPHERAL	*per;
	ADXF					adxf[MAX_ADXF];

	adxf[0] = ap->adxf[0];
	adxf[1] = ap->adxf[1];
	adxf[2] = ap->adxf[2];
	adxf[3] = ap->adxf[3];
	adxf[4] = ap->adxf[4];

	if (ap->disp_flag == ON)
		ap_disp_info(ap);
			
	per = UsrGetPeripheral(0);
	if (per->press & UTPAD_START)
		ap_clear_data(ap);

	if (per->press & UTPAD_L)
		ap->disp_flag = NOT_FLAG(ap->disp_flag);

	if (per->press & UTPAD_UP)
		return FALSE;

	/*	AFSファイルの読み込み開始	*/
	/*	Start to load AFS file		*/
	if (per->press & UTPAD_BUTTON1) {
		if (ADXF_Tell(adxf[0]) == ADXF_GetFsizeSct(adxf[0]))
			ADXF_Seek(adxf[0], 0, ADXF_SEEK_SET);
		ADXF_ReadNw(adxf[0], 100, ap->data_buf);
	}
	if (per->press & UTPAD_BUTTON2) {
		if (ADXF_Tell(adxf[1]) == ADXF_GetFsizeSct(adxf[1]))
			ADXF_Seek(adxf[1], 0, ADXF_SEEK_SET);
		ADXF_ReadNw(adxf[1], 100, ap->data_buf);
	}
	if (per->press & UTPAD_BUTTON3) {
		if (ADXF_Tell(adxf[2]) == ADXF_GetFsizeSct(adxf[2]))
			ADXF_Seek(adxf[2], 0, ADXF_SEEK_SET);
		ADXF_ReadNw(adxf[2], 100, ap->data_buf);
	}
	if (per->press & UTPAD_BUTTON4) {
		if (ADXF_Tell(adxf[3]) == ADXF_GetFsizeSct(adxf[3]))
			ADXF_Seek(adxf[3], 0, ADXF_SEEK_SET);
		ADXF_ReadNw(adxf[3], 100, ap->data_buf);
	}
	if (per->press & UTPAD_R) {
		if (ADXF_Tell(adxf[4]) == ADXF_GetFsizeSct(adxf[4]))
			ADXF_Seek(adxf[4], 0, ADXF_SEEK_SET);
		ADXF_ReadNw(adxf[4], 100, ap->data_buf);
	}

	/* CRI Middleware Library's Server function */
	ADXM_ExecMain();

	return TRUE;
}

/***
 *		メイン処理
 *		MAIN
 ***/
int main(void)
{
	AP_OBJ	*ap;
	Sint32	term_flag = OFF;
	Bool	ret;

	ap = &ap_obj;

	/*	エラーコールバック関数の登録		*/
	/*	Entry ADX error callback function	*/
	ADXM_SetCbErr(ap_adx_err_func, NULL);
	
	/*	システムの初期化										*/
	/*	Initialize System										*/
	UsrInitSystem(NULL, NULL);
	
	/*	ビデオの初期化											*/
	/*	Initialize Video System									*/
	UsrInitVideo(NULL, NULL);
	
	/*	サウンドの初期化										*/
	/*	Initialize Sound System									*/
	UsrInitSound(NULL, NULL);

	ApInitMw(ap);

	while (term_flag == OFF) {
		ApStart(ap);
		/*	cnt :frame count						*/
		/*	cnt=0:interlace	/ cnt>0:non interlace	*/
		UsrInitSync(2);
		for (;;) {
			UsrSyncFrame();
			UsrBeginDraw();
			ret = ApExec(ap);
			UsrEndDraw();

			/* 終了するかどうかの確認					*/
			/* Checks whether Usr module is terminated	*/
			if (UsrIsTerminated() == TRUE) {
				term_flag = ON;
			}
			
			if (ret == FALSE || term_flag == ON) {
				break;
			}
		}
		ApStop(ap);
	}
	/*	アプリケーション終了処理	*/
	/*	Finalize application		*/
	ApFinishMw(ap);			/*	ミドルウェアの終了				*/
							/*	Finalize Middleware				*/
	UsrFinishSound();		/*	サウンドシステムの終了処理		*/
							/*	Finalize sound system			*/
	UsrFinishVideo();		/*	ビデオの終了処理				*/
							/*	Finalize Video system			*/
	UsrFinishSystem();		/*	システムの終了処理				*/
							/*	Finalize system					*/
	return 0;
}
