#include "p_apps.h"
#include "PalmChip.h"

#include "p_dsp.h"

volatile DCHAR Dsp_iType;

static volatile DCHAR _iEncOutHead, _iEncOutTail, _iDecInHead, _iDecInTail;
static volatile DCHAR _iJitter;
static volatile BOOLEAN _bCngReceived, _bEncoding = FALSE, _bDecoding = FALSE;
#ifdef _USE_FXS
static volatile BOOLEAN _bDetecting = FALSE;
#endif

void DspClearDecodeData()
{
	while (!Dsp_bFinished);

	_iDecInHead = 0;
	_iDecInTail = 255;
}

void DspStart()
{
	DspDownloadCode(Dsp_cCodeSdramHi[Dsp_iType], Dsp_cCodeSdramLo[Dsp_iType], Dsp_cCodeSize[Dsp_iType]);

	_iJitter = Sys_iJitterSize + 1;
	_bCngReceived = FALSE;
	_bEncoding = FALSE;
	_bDecoding = FALSE;
#ifdef _USE_FXS
	_bDetecting = FALSE;
#endif
	Dsp_bFinished = TRUE;

	DspWriteDMC(PMIN_DTMF_CODE, 0xff);
	DspClearDecodeData();
	_iEncOutHead = 0;
	_iEncOutTail = 255;
	DspWriteDMC(PMIN_AEC_USAGE, ((Dsp_iOptions & USE_AEC_OR) ? 1 : 0));
	DspWriteDMC(PMIN_AGC_USAGE, ((Dsp_iOptions & USE_AGC_OR) ? 1 : 0));
	if (Dsp_iType == CODEC_G7231)
	{
#ifdef CALL_N2P
		DspWriteDMC(ENC_USE_HIGH_RATE, 1);		// always use highrate for N2P protocol
#else
		DspWriteDMC(ENC_USE_HIGH_RATE, ((Dsp_iOptions & USE_HIGH_RATE_OR) ? 1 : 0));
#endif
		DspWriteDMC(DEC_USE_POST_FILTER, 1);
	}

//	if (Dsp_iType == CODEC_G7231 || Dsp_iType == CODEC_ILBC)
//	{
//		DspWriteDMC(PMIN_AGC_USAGE, 1);
//	}
//	else
//	{
//		DspWriteDMC(PMIN_AGC_USAGE, ((Dsp_iOptions & USE_AGC_OR) ? 1 : 0));
//	}

	DspExecuteAndWait(Dsp_cCodecInit[Dsp_iType]);

#if defined CALL_WP || defined CALL_N2P
	DspWriteDMC(ENC_USE_VAD, 0);	// never use VAD with N2P and WP protocol
#else
	DspWriteDMC(ENC_USE_VAD, ((Dsp_iOptions & USE_VAD_OR) ? 1 : 0));
#endif

	DspWriteDMC(PMIN_AEC_USAGE, ((Dsp_iOptions & USE_AEC_OR) ? 1 : 0));
	DspWriteDMC(PMIN_AGC_USAGE, ((Dsp_iOptions & USE_AGC_OR) ? 1 : 0));
	
	DspWriteDMC(ENC_INPUT_SDRAM_HI, AC97_IN_SDRAM_HI);
	DspWriteDMC(ENC_OUTPUT_SDRAM_HI, DSP_OUTPUT_SDRAM_HI);
	DspWriteDMC(DEC_INPUT_SDRAM_HI, DSP_INPUT_SDRAM_HI);
	DspWriteDMC(DEC_OUTPUT_SDRAM_HI, AC97_OUT_SDRAM_HI);

#ifdef _USE_FXS_AG1170
	if (Ac97_iHandsetInputVol <= 2)
	{
		DspWriteDMC(PMIN_DTMF_AMP,6);
	}
	else if (Ac97_iHandsetInputVol <= 8)
	{
		DspWriteDMC(PMIN_DTMF_AMP,7);
	}
	else
	{
		DspWriteDMC(PMIN_DTMF_AMP,14);
	}
#else
	if (Ac97_iHandsetInputVol <= 6)
	{
		DspWriteDMC(PMIN_DTMF_AMP, 1);
	}
	else if (Ac97_iHandsetInputVol <= 9)
	{
		DspWriteDMC(PMIN_DTMF_AMP, 2);
	}
	else if (Ac97_iHandsetInputVol <= 12)
	{
		DspWriteDMC(PMIN_DTMF_AMP, 3);
	}
	else 
	{
		DspWriteDMC(PMIN_DTMF_AMP, 4);
	}
#endif
}

BOOLEAN DspHandleEncodeData()
{
	DCHAR iTail, iLength;

	iTail = _iEncOutTail+1;
	if (iTail != _iEncOutHead)
	{
		SdramRead(DSP_OUTPUT_SDRAM_HI, iTail, Dsp_iDecodeLenDword[Dsp_iType]);
		iLength = XBYTE[Sdram_pDataCache+Dsp_iDecodeLenPos[Dsp_iType]];
		OnOutgoingData(iLength, (PXCHAR)Sdram_pDataCache);
		_iEncOutTail = iTail;
		return TRUE;
	}
	return FALSE;
}

void DspHandleDecodeData(UCHAR iLen, PXCHAR pData)
{
	DCHAR iLength, iVadLength;

	iLength = iLen;
	iVadLength = Dsp_iVadLen[Dsp_iType];

	if (Ac97_iDtmfCode < DTMF_SIGNAL_DIAL)
	{
		_bCngReceived = FALSE;
		return;
	}

	if (_iDecInHead != _iDecInTail)
	{
		p_memcpy_x2x((PXCHAR)Sdram_pDataCache, pData, iLength);
//		p_memset_x((PXCHAR)Sdram_pDataCache, 0x7e, G711_LEN);
		USHORT2PXCHAR(iLength, (PXCHAR)(Sdram_pDataCache+Dsp_iDecodeLenPos[Dsp_iType]-1));
		SdramWrite(DSP_INPUT_SDRAM_HI, _iDecInHead, Dsp_iDecodeLenDword[Dsp_iType]);
		_iDecInHead ++;

		// check cng here
		if (_bCngReceived)
		{
			if (iLength > iVadLength)
			{
				_bCngReceived = FALSE;
			}
		}
		else
		{
			if (iLength == iVadLength)
			{
				_bCngReceived = TRUE;
			}
		}

		if (!_iDecInHead)
		{
			OutputVal(_iDecInTail, IDS_CHECK_POINT_3);
		}
/*		if (_iDecInHead - _iDecInTail > 8 + _iJitter * 8)
		{
			_iDecInTail ++;
			_bCngReceived = FALSE;
		}
*/
	}
	else
	{
		DspClearDecodeData();
		Ac97InitBuffer();
		OutputString(IDS_DECODE_OVERFLOW);
	}
}

#ifdef _USE_FXS
void _GetDtmfDetectResult()
{
	DCHAR iTmp;

	iTmp = (UCHAR)DspReadDMC(PMIN_DTMF_CODE);	//DtmfDetect Output
	if (iTmp == 0xff)	return;

	Slic_iDtmfKey = (UCHAR)DspReadDMC(PMIN_DTMF_CODE);	//DtmfDetect Output
	Slic_iDtmfKey --;
	DspWriteDMC(PMIN_DTMF_CODE, 0xff);
	if (Slic_iDtmfKey <= DTMF_SIGNAL_WELL)
	{
		Slic_bDtmfFlag = TRUE;
		Ac97_iDtmfCode = DTMF_SIGNAL_QUIET;
		Ac97_iDtmfDuration = 0;
	}
}
#endif

BOOLEAN _HasDecodeData()
{
/*
	DCHAR iTail;

	iTail = _iDecInTail + 1;
	if (iTail != _iDecInHead)
	{
		_bDecoding = TRUE;
		return TRUE;
	}
	return FALSE;
*/
	if (_iDecInHead - _iDecInTail > _iJitter)
	{
		_bDecoding = TRUE;
		return TRUE;
	}
	return FALSE;
}

void _SetEncodeFlag()
{
	if (_iEncOutHead != _iEncOutTail)
	{
		_bEncoding = TRUE;
	}
}

void DspCall()
{
	DspWriteDMC(DEC_INPUT_SDRAM_LO, _iDecInTail + 1);
	DspWriteDMC(DEC_OUTPUT_SDRAM_LO, Ac97_iBuf);
//	DspWriteDMC(ENC_INPUT_SDRAM_LO, Ac97_iBuf);
	DspWriteDMC(ENC_OUTPUT_SDRAM_LO, _iEncOutHead);

#ifdef _USE_FXS
	if (Task_bConnected)
	{
		if (_HasDecodeData())
		{	// (4.1)
			if (Sys_iDtmfType == DTMF_INBAND_AUDIO)
			{
				// call 4
				DspExecute(Dsp_cEntry_4[Dsp_iType]);
			}
			else
			{
				// call 18
				DspExecute(Dsp_cEntry_18[Dsp_iType]);
			}
		}
		else
		{
			if (Ac97_iDtmfDuration)
			{	
				DspWriteDMC(PMIN_TONE_AMP, Ac97_iDtmfCode);
				Ac97_iDtmfDuration --;
				if (Sys_iDtmfType == DTMF_INBAND_AUDIO)
				{
					// call 5
					DspExecute(Dsp_cEntry_5[Dsp_iType]);
				}
				else
				{
					// call 25
					DspExecute(Dsp_cEntry_25[Dsp_iType]);
				}
			}
			else
			{	// (4.2)
				if (_bCngReceived)
				{
					if (Sys_iDtmfType == DTMF_INBAND_AUDIO)
					{
						// call 7
						DspExecute(Dsp_cEntry_7[Dsp_iType]);
					}
					else
					{
						// call 19
						DspExecute(Dsp_cEntry_19[Dsp_iType]);
					}
				}
				else
				{
					if (Sys_iDtmfType == DTMF_INBAND_AUDIO)
					{
						// call 8
						DspExecute(Dsp_cEntry_8[Dsp_iType]);
					}
					else
					{
						// call 20
						DspExecute(Dsp_cEntry_20[Dsp_iType]);
					}
					_bCngReceived = TRUE;
				}
			}
		}
		_SetEncodeFlag();
	}
	else if (Task_bConnecting && !Task_bCaller)
	{	// (5.1)
		if (Ac97_iDtmfDuration)
		{
			DspWriteDMC(PMIN_TONE_AMP, Ac97_iDtmfCode);
			Ac97_iDtmfDuration --;
		}
		else
		{
			DspWriteDMC(PMIN_TONE_AMP, DTMF_SIGNAL_QUIET);
		}

		if ((Slic_iCidStatus & CID_STATUS_START_OR) && !(Slic_iCidStatus & CID_STATUS_FINISH_OR))
		{
			// call 22
			DspExecute(Dsp_cEntry_22[Dsp_iType]);
		}
		else
		{
			// call 12
			DspExecute(Dsp_cEntry_12[Dsp_iType]);
		}
		_SetEncodeFlag();

	}
	else
	{	
		if (_HasDecodeData())
		{	// (6.1)
			// call 9
			DspExecute(Dsp_cEntry_9[Dsp_iType]);
//			DspExecute(Dsp_cEntry_4[Dsp_iType]);	// Nic Bellamy <nicb-lists@vadacom.co.nz> change
		}
		else
		{	// (6.2) & (6.3)
			if (Ac97_iDtmfDuration)
			{
				DspWriteDMC(PMIN_TONE_AMP, Ac97_iDtmfCode);
				Ac97_iDtmfDuration --;
			}
			else
			{
				DspWriteDMC(PMIN_TONE_AMP, DTMF_SIGNAL_QUIET);
			}
			// call 24
			DspExecute(Dsp_cEntry_24[Dsp_iType]);
			_bDetecting = TRUE;
		}
		_SetEncodeFlag();
	}
#else
	if (Task_bConnected)
	{
		if (_HasDecodeData())
		{	// (1.1)
			// call 4
			DspExecute(Dsp_cEntry_4[Dsp_iType]);
		}
		else
		{
			if (Ac97_iDtmfDuration)
			{	// (1.2)
				DspWriteDMC(PMIN_TONE_AMP, Ac97_iDtmfCode);
				Ac97_iDtmfDuration --;
				if (Sys_iDtmfType == DTMF_INBAND_AUDIO)
				{
					// call 6
					DspExecute(Dsp_cEntry_6[Dsp_iType]);
				}
				else
				{
					// call 5
					DspExecute(Dsp_cEntry_5[Dsp_iType]);
				}
			}
			else
			{	// (1.3)
				if (_bCngReceived)
				{
					// call 7
					DspExecute(Dsp_cEntry_7[Dsp_iType]);
				}
				else
				{
					// call 8
					DspExecute(Dsp_cEntry_8[Dsp_iType]);
					_bCngReceived = TRUE;
				}
			}
		}
		_SetEncodeFlag();
	}
	else if (Sys_bHighSpeed && !Task_bCaller)
//	else if (Task_bConnecting && !Task_bCaller)
	{
		if (Task_iRingType == RING_TYPE_ADVANCED)
		{	// (2.1)
			if (_HasDecodeData())
			{
				// call 9
				DspExecute(Dsp_cEntry_9[Dsp_iType]);
			}
			else
			{
				// call 10
				DspExecute(Dsp_cEntry_10[Dsp_iType]);
			}
		}
		else
		{	// (2.2)
			if (Ac97_iDtmfDuration)
			{
				DspWriteDMC(PMIN_TONE_AMP, Ac97_iDtmfCode);
				Ac97_iDtmfDuration --;
			}
			else
			{
				DspWriteDMC(PMIN_TONE_AMP, DTMF_SIGNAL_QUIET);
			}
			if (Task_iRingType == RING_TYPE_DTMF)
			{	// (2.2.1)
				// call 6
				DspExecute(Dsp_cEntry_6[Dsp_iType]);
			}
			else if (Task_iRingType == RING_TYPE_DND)
			{	// (2.2.2)
				// call 12
				DspExecute(Dsp_cEntry_12[Dsp_iType]);
			}
			else if (Task_iRingType == RING_TYPE_USER)
			{	// (2.2.3)
				if (_HasDecodeData())
				{
					// call 13
					DspExecute(Dsp_cEntry_13[Dsp_iType]);
				}
				else
				{
					// call 12
					DspExecute(Dsp_cEntry_12[Dsp_iType]);
				}
			}
			_SetEncodeFlag();
		}
	}
	else
	{
		if (_HasDecodeData())
		{	// 3.1
			// call 9
			DspExecute(Dsp_cEntry_9[Dsp_iType]);
//			DspExecute(Dsp_cEntry_4[Dsp_iType]);	// Nic Bellamy <nicb-lists@vadacom.co.nz> change
		}
		else
		{	// 3.2 & 3.3
			if (Ac97_iDtmfDuration)
			{
				DspWriteDMC(PMIN_TONE_AMP, Ac97_iDtmfCode);
				Ac97_iDtmfDuration --;
			}
			else
			{
				DspWriteDMC(PMIN_TONE_AMP, DTMF_SIGNAL_QUIET);
			}
			// call 16
			DspExecute(Dsp_cEntry_16[Dsp_iType]);
		}
		_SetEncodeFlag();
	}
#endif	// _USE_FXS

	Dsp_bFinished = FALSE;
}

void DspHandleInterrupt()
{
	Dsp_bFinished = TRUE;
	if (_bEncoding)
	{
		_iEncOutHead ++;
		_bEncoding = FALSE;
#ifdef _USE_FXS
		_GetDtmfDetectResult();
#endif
	}
	if (_bDecoding)
	{
		_iDecInTail ++;
		_bDecoding = FALSE;
	}
#ifdef _USE_FXS
	if (_bDetecting)
	{
		_GetDtmfDetectResult();
		_bDetecting = FALSE;
	}
#endif
}

