/**************************************************************************//**
 * @file     avi.c
 * @brief    APIs support to play AVI file 
 *
 * SPDX-License-Identifier: Apache-2.0
 * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
/****************************************************************************
*                                                                           *
* Copyright (c) 2009 Nuvoton Tech. Corp. All rights reserved.               *
*                                                                           *
*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "N9H20.h"
#include "nvtloader.h"

#if defined(N9H20K3) || defined(N9H20K5)
static int _complete = 0;
static int _offset = 0;
static int _fd;
#endif

extern unsigned char kbuf[CP_SIZE];
extern BOOL bIsIceMode;
void initVPost(unsigned char*);


LCDFORMATEX lcdInfo;

static volatile BOOL bEscapeKeyPress=FALSE;
static volatile BOOL bSetVolume=FALSE;
UINT32 u16Volume = 0x1F;	// 60*63/100=; Linux driver default = 60 
// use callback function of AVI player to load kernel
#if defined(N9H20K3) || defined(N9H20K5)
void loadKernel(AVI_INFO_T *aviInfo)
{
	int bytes, result;

	if(bSetVolume==FALSE)
	{
		aviSetPlayVolume(u16Volume);
		bSetVolume = TRUE;
	}
	
	
	if(bEscapeKeyPress==TRUE)	
		return;
	//sysprintf("\n");
	if(!_complete) {
		if(_offset < CP_SIZE)
		{//1th, keep the original vector table in  SDRAM. 			
			result = fsReadFile(_fd, (kbuf + _offset), (CP_SIZE - _offset), &bytes);
		}	
		else
		{//2nd, 3rd, .... Copy the kernel content to address 16K, 32K, 	
			result = fsReadFile(_fd, (UINT8 *)_offset, CP_SIZE, &bytes);
		}	
		if(result == FS_OK)
			_offset += bytes;
		else
			_complete = 1;
	}
	if(bEscapeKeyPress==FALSE)
	{
#ifdef __CC__	
		result = 0;
#else
		result = kpi_read(KPI_NONBLOCK);	
#endif		
#if defined(__DEMO_MC__) || defined(__WIFI__)
		if(result == 8)	//Home key  
#elif defined(__SD2_DEMO__)
		if(result == 4)
#else
		if(result == 16)	//Home key
#endif		
		{//Stop AVI playback
			bEscapeKeyPress = TRUE;
			sysprintf("Key pressed %d\n", result);
			
			aviStopPlayFile();	
			
		}		
	}	
	return;
}

#endif

void loadKernelCont(int fd, int offset)
{	
	int bytes, result;
	
	while(1) {
		if(offset < CP_SIZE)		
			result = fsReadFile(fd, (kbuf + offset), (CP_SIZE - offset), &bytes);
		else
			result = fsReadFile(fd, (UINT8 *)offset, CP_SIZE, &bytes);	
		if(result == FS_OK)
			offset += bytes;
		else
			return;	
	}
}

void lcmFill2Dark(unsigned char* fb)
{
	lcdInfo.ucVASrcFormat = DRVVPOST_FRAME_YCBYCR;
	if(lcdInfo.ucVASrcFormat == DRVVPOST_FRAME_YCBYCR)
	{	
		UINT32 i;
		UINT32* ptBufAddr=(UINT32*)((UINT32)fb | 0x80000000);
		for(i=0;i<(PANEL_WIDTH * PANEL_HEIGHT * PANEL_BPP);i=i+4)
		{
			outpw(ptBufAddr, 0x80108010);
			ptBufAddr = ptBufAddr+1;		//2 pixels 
		}
	}
	else if(lcdInfo.ucVASrcFormat == DRVVPOST_FRAME_RGB565)
	{
		memset((char*)fb, 0, PANEL_WIDTH * PANEL_HEIGHT * PANEL_BPP);
	} 
}
/*=====================================================
	New Demo board supports amplifier control. 
##demo board	
	HP_DET: GPB2
			1: Earphone  detection
			0: No erephone detection
	SPK_EN: GPB3:
			1: Enable amplifier for speaker
			0: Disable amplifier 
##WINTEK LCM
	HP_DET: GPB2
			1: Earphone  detection
			0: No erephone detection
	SPK_EN: GPB3:
			1: Enable amplifier for speaker
			0: Disable amplifier 	
##128 package for VideoIN+8bit LCM
	HP_DET: GPE0
			1: Earphone  detection
			0: No erephone detection
	SPK_EN: GPE1:
			1: Enable amplifier for speaker
			0: Disable amplifier 			

##INCHu' demo board (SD2)
	HP_DET: GPD3
			1: No Earphone detection
			0: Earphone  detection 
	
	SPK_EN:	GPD4			
			1: Enable amplifier for speaker
			0: Disable amplifier 
										
=====================================================*/
void ampEnable(void)
{
	UINT16 u16HearPhone;		

	
#if defined(__IXL_WINTEK__)	
	gpio_setportdir(GPIO_PORTB, 0x04, 0x00);			//GPIOB2 input mode 
	gpio_readport(GPIO_PORTB, &u16HearPhone);
	if( (u16HearPhone & 0x04) ==0x00 )					
#elif ((defined(__GWMT9360A__) || defined(__GWMT9615A__)) && !defined(__SD2_DEMO__))  
	outp32(REG_GPEFUN, inp32(REG_GPEFUN) & (~(MF_GPE0 | MF_GPE1)));
	gpio_setportdir(GPIO_PORTE, 0x01, 0x00);			//GPIOE0 input mode 
	gpio_readport(GPIO_PORTE, &u16HearPhone);			//GPIOE0 for detect
	if( (u16HearPhone & 0x01) == 0x00)					//128 package for VideoIn and 8 bit LCM	
#elif defined(__SD2_DEMO__)
	if(bIsIceMode==TRUE)
		return; 	
	outp32(REG_GPDFUN, inp32(REG_GPDFUN) & (~(MF_GPD3 | MF_GPD4)));
	gpio_setportdir(GPIO_PORTD, 0x08, 0x00);			//GPIOD3 input mode 
	gpio_readport(GPIO_PORTD, &u16HearPhone);			//GPIOE0 for detect
	if( (u16HearPhone & 0x08) == 0x08 )					//DEMO board
#else
	gpio_setportdir(GPIO_PORTB, 0x04, 0x00);			//GPIOB2 input mode 
	gpio_readport(GPIO_PORTB, &u16HearPhone);
	if( (u16HearPhone & 0x04) == 0x00 )					//DEMO board 
#endif	
	{//Earphone Plug out
		//sysprintf("Earphone out\n");
	#if defined(__SD2_DEMO__)		
		gpio_setportval(GPIO_PORTD, 0x10, 0x10);        //GPIOD4 high to enable Amplifier 
		gpio_setportpull(GPIO_PORTD, 0x10, 0x10);		//GPIOD4 pull high
		gpio_setportdir(GPIO_PORTD, 0x010, 0x10);		//GPIOD4 output mode	
  	#elif ((defined(__GWMT9360A__) || defined(__GWMT9615A__)) && !defined(__SD2_DEMO__))
  		gpio_setportval(GPIO_PORTE, 0x02, 0x02);        	//GPIOE1 high to enable Amplifier 
		gpio_setportpull(GPIO_PORTE, 0x02, 0x02);		//GPIOE1 pull high
		gpio_setportdir(GPIO_PORTE, 0x02, 0x02);		//GPIOE1 output mode	
  	#else
		gpio_setportval(GPIO_PORTB, 0x08, 0x08);        	//GPIOB3 high to enable Amplifier 
		gpio_setportpull(GPIO_PORTB, 0x08, 0x08);		//GPIOB3 pull high
		gpio_setportdir(GPIO_PORTB, 0x08, 0x08);		//GPIOB3 output mode
	#endif	
	}
	else
	{
		//sysprintf("Earphone in\n");
	#if defined(__SD2_DEMO__)		
  		gpio_setportval(GPIO_PORTD, 0x10, 0x00);        //GPIOD4 low to disable Amplifier 
		gpio_setportpull(GPIO_PORTD, 0x10, 0x00);		//GPIOD4 don't pull high
		gpio_setportdir(GPIO_PORTD, 0x10, 0x10);		//GPIOD4 output mode 	
	#elif ((defined(__GWMT9360A__) || defined(__GWMT9615A__)) && !defined(__SD2_DEMO__)) 
  		gpio_setportval(GPIO_PORTE, 0x02, 0x00);        	//GPIOE1 low to disable Amplifier 
		gpio_setportpull(GPIO_PORTE, 0x02, 0x00);		//GPIOE1 don't pull high
		gpio_setportdir(GPIO_PORTE, 0x02, 0x02);		//GPIOE1 output mode
  	#else
		gpio_setportval(GPIO_PORTB, 0x08, 0x00);        	//GPIOB3 low to disable Amplifier 
		gpio_setportpull(GPIO_PORTB, 0x08, 0x00);		//GPIOB3 don't pull high
		gpio_setportdir(GPIO_PORTB, 0x08, 0x08);		//GPIOB3 output mode
	#endif	
	}
}

void startAmpEnableCheck(void)
{
	UINT32 u32ExtFreq;
	
	ampEnable();	
	
	u32ExtFreq = sysGetExternalClock()*1000;
	DBG_PRINTF("Timer 0 Test...\n");	
	sysSetTimerReferenceClock(TIMER0, u32ExtFreq); 			//External Crystal	
	sysStartTimer(TIMER0, 100, PERIODIC_MODE);				/* 100 ticks/per sec ==> 1tick/10ms */	
	sysSetTimerEvent(TIMER0, 10, (PVOID)ampEnable);	/* 10 ticks = 100ms call back */
}	
void ampDisable(void)
{
#if defined(__SD2_DEMO__)
	if(bIsIceMode==TRUE)
		gpio_setportval(GPIO_PORTD, 0x10, 0x00);        	//GPIOD4 low to disable Amplifier
#elif ((defined(__GWMT9360A__) || defined(__GWMT9615A__)) && !defined(__SD2_DEMO__)) 
	gpio_setportval(GPIO_PORTE, 0x02, 0x00);        	//GPIOE1 high to disable Amplifier 
#else
	gpio_setportval(GPIO_PORTB, 0x08, 0x00);        	//GPIOB2 low to disable Amplifier 
#endif	
}
/*
	In Demo board, change GPIOD1 from pull high 10K to pull low 10K.
	Defaule GPIOD1 is low (Turn off back light).
	After initialize VPOST and delay a period for panel show first frame ready.   	
	Turn on back light. (GPIOD1=1)
*/
void backLightEnable(void)
{
	/* 1. If backlight control signal is different from nuvoton��s demo board,
              please don't call this function and must implement another similar one to enable LCD backlight. */
	vpostEnaBacklight();
}

void AudioChanelControl(void)
{
#if defined(__IXL_WINTEK__)
	outp32(REG_GPAFUN, inp32(REG_GPAFUN) & (~MF_GPA6));		
	gpio_setportval(GPIO_PORTA, 0x40, 0x00);			//GPIOA6 output low 
	gpio_setportpull(GPIO_PORTA, 0x40, 0x00);			//GPIOA6 pull high disable 
	gpio_setportdir(GPIO_PORTA, 0x40, 0x40);			//GPIOA6 output mode
#endif
#if defined(__GWMT9360A__) || defined(__GWMT9615A__)
	
#endif
}
static UINT32 bIsInitVpost=FALSE;
void initVPostShowLogo(void)
{
	if(bIsInitVpost==FALSE)
	{
		bIsInitVpost = TRUE;
		//lcdInfo.ucVASrcFormat = DRVVPOST_FRAME_YCBYCR;	
		lcdInfo.ucVASrcFormat = DRVVPOST_FRAME_RGB565;	
		lcdInfo.nScreenWidth = PANEL_WIDTH;	
		lcdInfo.nScreenHeight = PANEL_HEIGHT;
		vpostLCMInit(&lcdInfo, (UINT32*)FB_ADDR);
		/* 1. If backlight control signal is different from nuvoton��s demo board,
           please don't call this function and must implement another similar one to enable LCD backlight. */
        vpostEnaBacklight();
	}	
}

/*
void moveFrameBufferData(PUINT8 pu8Src, UINT32 u32Len)
{
	UINT32 u32Idx;
	PUINT32 pu32Src, pu32Dst;
	pu32Src = (PUINT32)pu8Src;
	pu32Dst = (PUINT32)0x500000;
	printf("Src addr = 0x%x\n", pu32Src);
	printf("Dst addr = 0x%x\n", pu32Dst);
	printf("Len = 0x%x\n", u32Len);
	for(u32Idx=0; u32Idx<u32Len; u32Idx= u32Idx+2)
	{
		*pu32Dst = *pu32Src;
		pu32Src++;
		pu32Dst++;
	}
}
*/
#if defined(N9H20K3) || defined(N9H20K5)
void playAni(int kfd, char* pcString)
{
	char aniPath[64];
		
	lcdInfo.ucVASrcFormat = DRVVPOST_FRAME_YCBYCR;	
	//cdInfo.ucVASrcFormat = DRVVPOST_FRAME_RGB565;	
	
//	spuOpen(eDRVSPU_FREQ_8000);
//	spuDacOn(1);
//	spuIoctl(SPU_IOCTL_SET_VOLUME, 0x1F, 0x1F);
		
#if defined(__LCM_800x600__) || defined(__LCM_800x480__)
	outp32(REG_GPDFUN, inp32(REG_GPDFUN) & (~MF_GPD0));		//!!!! Remember switch GPIOD 0 to GPIO. It will cause the ICE crash. 
	gpio_setportval(GPIO_PORTD, 0x01, 0x01);			//GPIOD0 output mode 
	gpio_setportpull(GPIO_PORTD, 0x01, 0x01);			//GPIOD0 pull high
	gpio_setportdir(GPIO_PORTD, 0x01, 0x01);			//GPIOD0 output mode
#endif		
	fsAsciiToUnicode(pcString, aniPath, TRUE);
	
	startAmpEnableCheck();	
	_fd = kfd; // let callback function know the file descriptor
	bEscapeKeyPress = FALSE;
   	if (aviPlayFile(aniPath, 0, 0, DIRECT_RGB565, (kfd > 0) ? loadKernel : NULL) < 0)
		DBG_PRINTF("Playback failed\n");
	else
		DBG_PRINTF("Playback done.\n");
	ampDisable();
	
	//moveFrameBufferData(fb, PANEL_WIDTH * PANEL_HEIGHT * PANEL_BPP);
	
	// If movie is too short for callback function to load kernel to SDRAM, keep working...
	if(kfd > 0 && _complete == 0) {
		loadKernelCont(kfd, _offset);
	}
	
	if(kfd > 0) {
		fsCloseFile(_fd);
	}
	
	return;

}
#endif