//
// MODULE  : STAUDIO.C
//	PURPOSE : Audio Routines
//	AUTHOR  : JBS Yadawa
// CREATED :  7/20/96
//
//
//	Copyright (C) 1996 SGS-THOMSON Microelectronics
//
//
//	REVISION HISTORY :
//
//	DATE     :
//
//	COMMENTS :
//

#include "common.h"
#include "stdefs.h"
#include "staudio.h"
#include "debug.h"
#include "error.h"
#include "board.h"
#include "sti3520A.h"
#include <dos.h> ///////////

static PAUDIO pAudio;
#define SLOW_MODE	0
#define PLAY_MODE	1
#define FAST_MODE	2

#define IT_A        0 // interrupt detected

void AudioOpen(PAUDIO pAud)
{                         
	pAudio = pAud;
	pAudio->AudioState = AUDIO_POWER_UP;
	pAudio->IntAudio = NO_IT_A;
	pAudio->MaskItAudio = 0;
	pAudio->ErrorMsg = NO_ERROR;
	pAudio->FirstPTS = FALSE;			   // First PTS not reached yet
	pAudio->mute = FALSE;
	pAudio->Stepped = FALSE;
	pAudio->FrameCount = 0;
}

void AudioClose(void)
{
}

void AudioInitDecoder(WORD StreamType)
{   
/*
#if 0
	pAudio->StrType = StreamType;
	switch(pAudio->AudioState) {
	case AUDIO_POWER_UP:
		BoardWriteAudio(RESET, 1);	   // reset the decoder
//ALTERAClearPendingAudioIT(); // Clear pending audio interrupt generated by soft reset
		BoardWriteAudio(INTR_EN, 0);  // disable all interupts
		BoardWriteAudio(INTR_EN + LSB, 0);
		BoardWriteAudio(PLAY, 0);	   // disable play output
		BoardWriteAudio(MUTE, 0);	   // do not mute output. LRclk and Sclk Stopped here
		BoardWriteAudio(INVERT_SCLK, 0);	// standard
		BoardWriteAudio(INVERT_LRCLK, 1);// standard
#ifndef VALID3520
		//**************************************************************
		// Philips TDA1311 is a 16 bit DAC (oversampling 1x, 2x, 4x, 8x)
		// -> LRCLK = SCLK / 32
		// -> SCLK  = PCMCLK / 8 (8 times oversampling => PCM_DIV = 3)
		// => PCMCLK = 256 * Sampling Frequency
		//**************************************************************
		BoardWriteAudio(PCM_DIV, 3);
		BoardWriteAudio(PCM_ORD, 0);	// MSB first
		BoardWriteAudio(PCM_18,  0);	// 16 bits of PCM data
		BoardWriteAudio(FORMAT,  0);	// I2S output format
		BoardWriteAudio(DIF,     0);	// Optionnal in 16 bit output
#else
		//**************************************************************
		// Crystal CS4330 is an 18 bit DAC (oversampling 1x, 4x, 6x, 8x)
		// -> LRCLK = SCLK / 64
		// -> SCLK  = PCMCLK / 4 (4 times oversampling => PCM_DIV = 1)
		// => PCMCLK = 256 * Sampling Frequency
		//**************************************************************
		BoardWriteAudio(PCM_DIV, 1);
		BoardWriteAudio(PCM_ORD, 0);
		BoardWriteAudio(PCM_18,  1);	// 18 bits of PCM data
		BoardWriteAudio(FORMAT,  0);	// I2S output format
		BoardWriteAudio(DIF,     0);	// Optionnal in 16 bit
#endif
		BoardWriteAudio(STR_SEL,  0);	// Default Stream Type is audio elem stream
		BoardWriteAudio(CRC_ECM,  1);	// mute on CRC error correction
		BoardWriteAudio(SYNC_ECM, 1);	// mute if Sync lost
		BoardWriteAudio(SYNCHRO_CONFIRM, 1);	// synchro confirmation mode
		BoardWriteAudio(SYNC_REG, 0x3F);	// layer, bitrate, fs fields not used
		BoardWriteAudio(PACKET_SYNC_CHOICE, 0);// multiplexed stream
		BoardWriteAudio(LATENCY, 0x0);   // Low Lattency decoding
		BoardWriteAudio(SYNC_LCK, 0x2);	// locked after 2 good Sync
		BoardWriteAudio(SIN_EN, 0x01);	  // Serial data input to enable bit buffer access
		BoardWriteAudio(AUDIO_ID_EN, 0x0);// ignore audio stream ID
		BoardWriteAudio(AUDIO_ID, 0x0);	 // audio stream ID ignored
		BoardWriteAudio(FREE_FORM_H, 0x0);// not free format
		BoardWriteAudio(FREE_FORM_L, 0x0);
		BoardWriteAudio(DUAL_REG, 0);  // Select Stereo Mode
		AudioSetSTCParameters(44100UL);
		BoardAudioSetSamplingFrequency(44100UL);
		pAudio->FrameCount = 0;	   // Reset Frame Count.
		pAudio->AudioState = AUDIO_INIT;
		break;
	default:
		break;
	}
#else
		BoardWriteAudio(0xF0, 1);	   // reset the decoder
		BoardWriteAudio(0xC6, 0);	   
		BoardWriteAudio(0xEF, 1);	   
		BoardWriteAudio(PCM_DIV, 2);
		BoardWriteAudio(0x9f, 0);
		BoardWriteAudio(0x99, 0);
		BoardWriteAudio(0xB6, 3);
		BoardWriteAudio(0x9e, 0);
		BoardWriteAudio(0xa0, 0);
		BoardWriteAudio(0x91, 0);
		BoardWriteAudio(0xb8, 0);
		BoardWriteAudio(0x96, 1);
		BoardWriteAudio(0xd3, 0);
		BoardWriteAudio(0xac, 0);
		BoardWriteAudio(0xc4, 0);
		BoardWriteAudio(0xc2, 1);
		BoardWriteAudio(0xAE, 1);

#endif	
*/
}

WORD AudioTestReg(void)
{     
#if 0
	WORD ReadValue;
	BoardWriteAudio(ATTEN_L, 0x55);
	BoardWriteAudio(ATTEN_R, 0xAA);
	ReadValue = BoardReadAudio(ATTEN_L);
	if ((ReadValue & 0x3F) != 0x15)
		goto Error;
	ReadValue = BoardReadAudio(ATTEN_R);
	if ((ReadValue & 0x3F) != 0x2A)
		goto Error;

	return NO_ERROR;

Error :
	SetErrorCode(ERR_AUDIO_REG_TEST_FAILED);
	return BAD_REG_A;
#else
	return NO_ERROR;
#endif
}

WORD AudioTest(void)
{   
#if 0
	WORD TestResult;
	TestResult = AudioTestReg();
	if (TestResult != NO_ERROR)
		return TestResult;
	else {
#ifdef DOSAPP
		if (AudioTestInt(pAudio) == NO_IT_A)
			return NO_IT_A;
		else
#endif
			return NO_ERROR;
	}
#else
	return NO_ERROR;
#endif	
}

WORD AudioTestInt(void)
{
	WORD err = NO_ERROR;
#if 0
	U8  Threshold;
	WORD a = 0;

	pAudio->MaskItAudio = FIFT;
	Threshold = BoardReadAudio(FIFO_IN_TRESHOLD);
	//---- Configure audio
	BoardWriteAudio(PLAY,  0x00);
	BoardWriteAudio(FIFO_IN_TRESHOLD, 0x01);
	//---- Enable FIFO full interrupt
	BoardWriteAudio(INTR_EN, 0x00);
	BoardWriteAudio(INTR_EN + LSB, 0x10);
	//---- Write a byte to force an interrupt
	BoardWriteAudio(DATA_IN, 0x00);
	// wait for occurrence of first audio interrupt
	while (pAudio->IntAudio == NO_IT_A) {
		Delay(1000);
		a++;						  /* incremented every 1 ms */
		if (a >= 1000) {
			DPF((Trace, "AudioTestInt failed !!"));
			SetErrorCode(ERR_NO_AUDIO_INTR);
			err = NO_IT_A; 	/* No interrupt */
			break;
		}
	}
	// Restore Interrupt mask
	pAudio->MaskItAudio = 0;
	AudioMaskInt();
	BoardWriteAudio(FIFO_IN_TRESHOLD, Threshold);
	BoardReadAudio(INTR);		   /* to clear audio interrupts flags */
#endif	
	return err;
}

// Set the decoding mode and parameters

void AudioSetMode(WORD Mode, WORD param)
{     
#if 0
	pAudio->DecodeMode = Mode;
	switch (pAudio->DecodeMode) {
	case PLAY_MODE:
		BoardWriteAudio(MUTE, 0);
		pAudio->fastForward = 0;
		pAudio->decSlowDown = 0;
		break;
	case FAST_MODE:
		pAudio->fastForward = 1;
		pAudio->decSlowDown = 0;
		break;
	case SLOW_MODE:
		pAudio->fastForward = 0;
		pAudio->decSlowDown = param;
		break;
	}
#endif	
}

// Decode
void AudioDecode(void)
{     
#if 0
	switch (pAudio->AudioState)	{
	case AUDIO_POWER_UP:
		break;
	case AUDIO_INIT:
		// Change in synchro + buffer over BALF +PTS
		pAudio->MaskItAudio = SYNC|BOF|PCMU|CRC| PTS;
		BoardWriteAudio(INTR_EN, (BYTE)(pAudio->MaskItAudio & 0xFF));
		BoardWriteAudio(INTR_EN + LSB, (BYTE)(pAudio->MaskItAudio >> 8 ));
//yg		BoardWriteAudio(MUTE, 1); 	// This Starts SClk and LRClk outputs
		BoardWriteAudio(PLAY, 1);	// Start decoding Output is Mute
		pAudio->AudioState = AUDIO_STC_INIT;
		break;
	case AUDIO_STC_INIT:
		pAudio->AudioState = AUDIO_DECODE;
		BoardWriteAudio(PLAY, 1);	// Restart decoding (decoding had been stopped when first audio PTS detected)
		BoardWriteAudio(MUTE, 0);	// Stop Muting output
		break;
	case AUDIO_DECODE:
		break;
	case AUDIO_PAUSE:
	case AUDIO_STEP:
		BoardWriteAudio(PLAY, 1);
		BoardWriteAudio(MUTE, 0);
		pAudio->AudioState = AUDIO_DECODE;
		break;
	}
#endif	
}

void AudioStep(void)
{     
#if 0
	BoardWriteAudio(MUTE, 0);
	BoardWriteAudio(PLAY, 1);
	pAudio->AudioState = AUDIO_STEP;
	pAudio->Stepped = FALSE;
#endif	
}

void AudioStop(void)
{     
#if 0
	switch(pAudio->AudioState) {
	case AUDIO_POWER_UP:
		break;
	case AUDIO_INIT:
		break;
	case AUDIO_STC_INIT:
	case AUDIO_DECODE:
		pAudio->AudioState = AUDIO_POWER_UP;
		AudioInitDecoder(pAudio, pAudio->StrType);
		break;
	}
#endif	
}

void AudioPause(void)
{     
#if 0
	switch(pAudio->AudioState) {
	case AUDIO_POWER_UP: /* After reset */
	case AUDIO_INIT:		 /* Initialisation + test of the decoders */
	case AUDIO_STC_INIT: /* STC of audio decoder initialized */
	case AUDIO_DECODE:	 /* Normal decode */
		BoardWriteAudio(MUTE, 1);
		BoardWriteAudio(PLAY, 0);
		pAudio->AudioState = AUDIO_PAUSE;
		break;
	}
#endif	
}

WORD AudioGetState(void)
{
	return ( pAudio->AudioState);
}

void AudioSetSTCParameters(DWORD SampFreq)
{   
#if 0
	// Note :
	// STCCLK = PCMCLK (fixed inside STi3520A)
	// (PCMCLK * inc) / div = 90kHz
	switch(SampFreq){
	case 32000UL:
		// PCMCLK = 256 * 32   = 8192 kHz,    inc = 45, div = 4096 -> 90kHz
		BoardWriteAudio(STC_INC,  45);
		BoardWriteAudio(STC_DIVH, 0x10);
		BoardWriteAudio(STC_DIVL, 0x00);
		break;

	case 44100UL:
		// PCMCLK = 256 * 44.1 = 11289.6 kHz, inc = 25, div = 3136 -> 90kHz
		BoardWriteAudio(STC_INC,  25);
		BoardWriteAudio(STC_DIVH, 0x0C);
		BoardWriteAudio(STC_DIVL, 0x40);
		break;

	case 48000UL:
		// PCMCLK = 256 * 48   = 12288 kHz,   inc = 15, div = 2048 -> 90kHz
		BoardWriteAudio(STC_INC,  15);
		BoardWriteAudio(STC_DIVH, 0x08);
		BoardWriteAudio(STC_DIVL, 0x00);
		break;

	default :
		break;
	}

	BoardWriteAudio(STC_CTL, 0x40);	// Load STC_VID on rising edge of VSYNC
#endif	
}
DWORD AudioGetSTC(void)
{   
#if 0
	DWORD  stc;
	WORD	 j;

	BoardWriteAudio(STC_CTL, 0x44);	// load current STC value to STC
	for ( j = 0; j < 0xF; j++)
		;
	stc = ( BoardReadAudio(STC_3 ) & 0xFFL ) << 24;
	stc = stc | ( ( BoardReadAudio(STC_2 ) & 0xFFL ) << 16);
	stc = stc | ( ( BoardReadAudio(STC_1 ) & 0xFFL ) << 8);
	stc = stc | ( BoardReadAudio(STC_0 ) & 0xFFL);
	return ( stc);
#else
	return 0;
#endif	
}

DWORD AudioGetVideoSTC(void)
{            
#if 0
	DWORD stc;
	WORD	j;

	BoardWriteAudio(STC_CTL, 0x48);	// load STC_VID to STC, Mode 0 mapping
//	BoardWriteAudio(STC_CTL, 0x44);  accu
//	BoardWriteAudio(STC_CTL, 0x50);
	for ( j = 0; j < 0xF; j++)
		;
/*
	stc = ( BoardReadAudio(STC_3 ) & 0xFFL ) << 24;
	stc = stc | ((BoardReadAudio(STC_2) & 0xFFL ) << 16);
	stc = stc | ((BoardReadAudio(STC_1) & 0xFFL ) << 8);
	stc = stc | ((BoardReadAudio(STC_0) & 0xFFL ));
*/
	stc =       ( BoardReadAudio(STC_0) & 0xFFL ) << 0;
	stc = stc | ((BoardReadAudio(STC_1) & 0xFFL ) << 8);
	stc = stc | ((BoardReadAudio(STC_2) & 0xFFL ) << 16);
	stc = stc | ((BoardReadAudio(STC_3) & 0xFFL ) << 24);
	return stc;
#else 
	return 0;
#endif	
}

void AudioInitSTC(DWORD stc)
{            
#if 0
	BoardWriteAudio(STC_0, (U8)(stc & 0xFFL));
	stc >>= 8;
	BoardWriteAudio(STC_1, (U8)(stc & 0xFFL));
	stc >>= 8;
	BoardWriteAudio(STC_2, (U8)(stc & 0xFFL));
	stc >>= 8;
	BoardWriteAudio(STC_3, (U8)(stc & 0xFFL));
	BoardWriteAudio(STC_CTL, 0x41);	// load STC to accumulator,
#endif	
}

DWORD AudioGetPTS(void)
{
	return pAudio->PtsAudio;
}

WORD AudioGetErrorMsg(void)
{
	return pAudio->ErrorMsg;
}

void AudioSetRightVolume(WORD volume)
{   
#if 0
	BoardWriteAudio(ATTEN_R, (BYTE)volume);
#endif
}

void AudioSetLeftVolume(WORD volume)
{     
#if 0
	BoardWriteAudio(ATTEN_L, (BYTE)volume);
#endif
}

void AudioMute(void)
{   
#if 0
	if (pAudio->mute) {
		BoardWriteAudio(MUTE, 0);
		pAudio->mute = FALSE;
	}
	else {
		BoardWriteAudio(MUTE, 1);
		pAudio->mute = TRUE;
	}
#endif	
}

BOOL AudioIsFirstPTS(void)
{
	return pAudio->FirstPTS;
}

void AudioSetStreamType(WORD StrType)
{   
#if 0
	BoardWriteAudio(STR_SEL, (BYTE)StrType);
#endif
}
void AudioInitPesParser (WORD StreamType)
{     
#if 0
	switch(StreamType)
	{
		case SYSTEM_STREAM:
		case VIDEO_PACKET:
		case AUDIO_PACKET:
		case VIDEO_PES:
		case AUDIO_PES:

			 BoardWriteAudio( STR_SEL, 1);
		break;
		case DUAL_PES:
			 BoardWriteAudio( STR_SEL, 4);
		break;
		case DUAL_ES:
			 BoardWriteAudio( STR_SEL, 0);
		break;
		case VIDEO_STREAM:
		case AUDIO_STREAM:
			 BoardWriteAudio( STR_SEL, 0);
		break;

	}
#endif	
}
void AudioMaskInt(void)
{     
#if 0
	BoardWriteAudio(INTR_EN, 0);
	BoardWriteAudio(INTR_EN + LSB, 0);
#endif
}

void AudioRestoreInt(void)
{   
#if 0
//HostDisplay(DISPLAY_FASTEST, "!%x!", pAudio->MaskItAudio);
	BoardWriteAudio(INTR_EN, (BYTE)(pAudio->MaskItAudio & 0xFF));
	BoardWriteAudio(INTR_EN + LSB, (BYTE)(pAudio->MaskItAudio >> 8));
#endif
}

BOOL AudioAudioInt(void)
{   
#if 0
	WORD     int_stat_reg, i;
	BOOLEAN	bAudioIntr = FALSE;

	// Read the interrupt status register
	int_stat_reg = BoardReadAudio(INTR);
	i = BoardReadAudio(INTR + LSB);
	i = i << 8;
	int_stat_reg = ( int_stat_reg & 0xFF ) | i;
	int_stat_reg = int_stat_reg & pAudio->MaskItAudio;	/* Mask the IT not used */
	if(int_stat_reg)
		bAudioIntr = TRUE;

	/******************************************************/
	/** FIFO FULL used to test audio interrupt generation**/
	/******************************************************/
	if (int_stat_reg & FIFT) {
		pAudio->IntAudio = IT_A;
	}
	/******************************************************/
	/**                   CHANGE SYNCHRO                 **/
	/******************************************************/
	if (int_stat_reg & SYNC) {
		i = BoardReadAudio(SYNC_ST);	// Synchronization status
		if ((i & 0x3) == 3)	{	   // Locked
		// Disable Change in synchro
			pAudio->MaskItAudio = pAudio->MaskItAudio & NSYNC;
			// Next Interrupt should be change in sampling freq
			pAudio->MaskItAudio = pAudio->MaskItAudio | SAMP;
		}
	}

	/******************************************************/
	/**             CHANGE IN SAMPLING FREQUENCY         **/
	/******************************************************/
	if (int_stat_reg & SAMP) {
		i = BoardReadAudio(PCM_FS ) & 0x3;	// Get Sampling frequency
		switch(i) {
		case 0 :
			BoardAudioSetSamplingFrequency(44100UL);
			AudioSetSTCParameters(44100UL);
			break;
		case 1 :
			BoardAudioSetSamplingFrequency(48000UL);
			AudioSetSTCParameters(48000UL);
			break;
		case 2 :
			BoardAudioSetSamplingFrequency(32000UL);
			AudioSetSTCParameters(32000UL);
			break;
		default :
			break;
		}
		// Disable change in sampling frequency
		pAudio->MaskItAudio = pAudio->MaskItAudio & NSAMP;
	}

	/******************************************************/
	/**                   CRC error                      **/
	/******************************************************/
	if (int_stat_reg & CRC)	{
	}

	/******************************************************/
	/**                   PCM Underflow                  **/
	/******************************************************/
	if (int_stat_reg & PCMU) {
	}

	/******************************************************/
	/**                  Begining of Frame               **/
	/******************************************************/
	if (int_stat_reg & BOF)	{
		DWORD STC = AudioGetVideoSTC();
		static DWORD STCOld;

//		HostDisplay(DISPLAY_FASTEST, "STCBOF = %8lu D = %5ld\r\n", STC, STC - STCOld);
//		STCOld = STC;

		// Check if stepping
		if ((pAudio->AudioState == AUDIO_STEP) && (pAudio->Stepped == FALSE)) {
			BoardWriteAudio(MUTE, 1);
			BoardWriteAudio(PLAY, 0);
			pAudio->Stepped = TRUE;
		}
		// If Slow motion or Fast forward, Mute Audio
		if ( pAudio->DecodeMode != PLAY_MODE ) {
			BoardWriteAudio(MUTE, 1);
			pAudio->mute = TRUE;
			if ((pAudio->FrameCount % 4) && (pAudio->fastForward))
				BoardWriteAudio(SKIP, 1);
			else if ((pAudio->DecodeMode == SLOW_MODE ) &&
							 ((pAudio->FrameCount % (pAudio->decSlowDown + 1)) != 0))
				BoardWriteAudio(REPEAT, 1);
		}

		pAudio->FrameCount++;			   // Increment Frame Count
	}

	/******************************************************/
	/**                   PTS detected                   **/
	/******************************************************/
	if ( int_stat_reg & PTS )	{
		DWORD pts;
//DBG1('p');
/*
		BoardReadAudio(PTS_4);	   // To clear pts interrupt
		pts = (BoardReadAudio(PTS_3) & 0xFFL) << 24;
		pts = pts | ((BoardReadAudio(PTS_2 ) & 0xFFL) << 16);
		pts = pts | ((BoardReadAudio(PTS_1 ) & 0xFFL) << 8);
		pts = pts | ( BoardReadAudio(PTS_0 ) & 0xFFL);
*/
		pts =        (BoardReadAudio(PTS_0) & 0xFFL) << 0;
		pts = pts | ((BoardReadAudio(PTS_1) & 0xFFL) << 8);
		pts = pts | ((BoardReadAudio(PTS_2) & 0xFFL) << 16);
		pts = pts | ((BoardReadAudio(PTS_3) & 0xFFL) << 24);
		BoardReadAudio(PTS_4);	   // To clear pts interrupt

		pAudio->PtsAudio = pts;
		if (pAudio->AudioState == AUDIO_STC_INIT) {
			pAudio->FirstPTS = TRUE;
//yg			BoardWriteAudio(PLAY, 0);
		}
		if (pAudio->AudioState == AUDIO_DECODE)	{
//			HostDirectPutChar('P', BLACK, LIGHTBLUE);
			AudioInitSTC ( pts);
//			DWORD STC = AudioGetVideoSTC();
//			HostDisplay(DISPLAY_FASTEST, "STC = %8lu PTSA = %8lu D = %8ld\r\n", STC, pts, STC - pts);
		}
	}

	return bAudioIntr;
#else
	return FALSE;
#endif	
}


