/*
 * ProgTools.c
 *
 *  Created on: 9 Nov 2015
 *      Author: DGonzalez
 */


#include "chip.h"
#include "pe0003.h"
#include "pe0003_config.h"
#include "ftdi.h"
#include "cbus.h"
#include "gpio.h"
#include "timer.h"
#include "lpc_types.h"

#include "mon_file.h"
#include "mon_general.h"


#include "ProgTools.h"
#include "Settings.h"
#include "Registers.h"


//-------------------------------------------------------------------
//
//		MENUES
//
//-------------------------------------------------------------------

uint8_t Convert_SourceModeReg(uint8_t opt);
uint8_t Convert_DestinationModeReg(uint8_t opt);
uint8_t Convert_InputOutputReg(uint8_t opt);


uint8_t Menu_DefaultSelection(uint8_t defOpt)
{
	while(defOpt == 0)
	{
		mprintf("\n");
		mprintf("Select configuration:\n");
		mprintf("	1) Custom configuration\n");
		mprintf("	2) G279A encoder\n");
		mprintf("	3) G279A decoder\n");
		mscanf("%d", defOpt);
	}

	return defOpt;
}




uint8_t Menu_SourceMode(uint8_t defOpt)
{
	while(defOpt == 0)
	{
		mprintf("\n");
		mprintf("Select signal audio source:\n");
		mprintf("	1) C-BUS Audio In FIFO\n");
		mprintf("	2) Analogue audio input\n");
		mscanf("%d", defOpt);
		if (defOpt > 2)
			defOpt = 0;
	}

	return Convert_SourceModeReg(defOpt);
}



uint8_t Convert_SourceModeReg(uint8_t opt)
{
	uint8_t xchVal[] = {
			0b0001,		/*C-BUS Audio In FIFO*/
			0b0010		/*Analogue audio input*/
	};

	return xchVal[opt];
}



uint8_t Menu_DestinationMode(uint8_t defOpt)
{
	while(defOpt == 0)
	{
		mprintf("\n");
		mprintf("Select signal audio destination:\n");
		mprintf(	"1) C-BUS Audio Out FIFO\n");
		mprintf(	"2) Analogue audio output, no monitor output\n");
		mprintf(	"3) C-BUS analogue audio output, no monitor output\n");
		mprintf(	"4) External PCM, no monitor output\n");
		mprintf(	"5) External PCM and C-BUS no monitor\n");
		mprintf(	"6)	External PCM and analogue audio output, no monitor output\n");
		mprintf(	"7)	External PCM, analogue audio output and C-BUS, no monitor output\n");
		mprintf(	"8) Monitor output enabled, all other audio destinations disabled\n");
		mprintf(	"9) C-Bus - Audio outFIFO, monitor enabled\n");
		mprintf(	"10) Analogue Output, monitor enabled\n");
		mprintf(	"11) C-BUS, Analogue output, monitor enabled\n");
		mprintf(	"12) External PCM, monitor enabled\n");
		mprintf(	"13) External PCM and C-BUS, monitor enabled\n");
		mprintf(	"14) External PCM and Analogue output, monitor enabled\n");
		mprintf(	"15) PCM, Analogue, C-BUS, monitor enabled\n");
		mscanf("%d", defOpt);
		if (defOpt > 15)
			defOpt = 0;
	}

	return Convert_DestinationModeReg(defOpt);
}


uint8_t Convert_DestinationModeReg(uint8_t opt)
{
	uint8_t xchVal[] = {
			0b0000, 	/*Null value*/
			0b0001,		/*C-BUS Audio Out FIFO*/
			0b0010,		/*Analogue audio output, no monitor output*/
			0b0011, 		/*C-BUS analogue audio output, no monitor output*/
			0b0100,		/*External PCM, no monitor output*/
			0b0101,		/*External PCM and C-BUS no monitor*/
			0b0110,		/*External PCM and analogue audio output, no monitor output*/
			0b0111,		/*External PCM, analogue audio output and C-BUS, no monitor output*/
			0b1000,		/*Monitor output enabled, all other audio destinations disabled*/
			0b1001,		/*C-Bus - Audio outFIFO, monitor enabled*/
			0b1010,		/*Analogue Output, monitor enabled*/
			0b1011,		/*C-BUS, Analogue output, monitor enabled*/
			0b1100,		/*External PCM, monitor enabled*/
			0b1101,		/*External PCM and C-BUS, monitor enabled*/
			0b1110,		/*External PCM and Analogue output, monitor enabled*/
			0b1111		/*PCM, Analogue, C-BUS, monitor enabled*/
	};

	return xchVal[opt];
}


/**
 * Input or Output Registers Menu
 * @param defOpt - Default selection menu, 0 if menu enable
 * @return value of Input register
 */
uint8_t Menu_InputOutputReg(uint8_t defOpt)
{
	while(defOpt == 0)
	{
		mprintf("\n");
		mprintf("Select input mode:\n");
		mprintf("	1)	Unpacked G279A\n");
		mprintf("	2) Packed G279A\n");
		mprintf("	3) Unpacked G711A\n");
		mprintf("	4) Packed G711A\n");
		mprintf("	5) Unpacked G711A with XOR\n");
		mprintf("	6) Packed G711A with XOR\n");
		mprintf("	7) Unpacked G711U\n");
		mprintf("	8) Packed G711U\n");
		mprintf("	9) Unpacked G711U with XOR\n");
		mprintf("	10) Packed G711U with XOR\n");
		mprintf("	11) Unpacked CVSD\n");
		mprintf("	12) Packed CVSD\n");
		mprintf("	13) 16 bit signed linear PCM\n");
		mprintf("	14)	16 bit unsigned linear PCM\n");
		mprintf("	15) 16 bit signed linear PCM Bit reversed\n");
		mprintf("	16) 16 bit unsigned linear PCM Bit reversed\n");
		mscanf("%d", defOpt);
		if (defOpt > 16)
			defOpt = 0;
	}

	return Convert_InputOutputReg(defOpt);
}


/**
 * Turn menu values into Input or Output register values
 * @param opt - Menu selected value
 * @return Value of the Input Register
 */
uint8_t Convert_InputOutputReg(uint8_t opt)
{
	uint8_t xchVal[] = {
			0x00, 	/*Null value*/
			0x00,	/*Unpacked G279A*/
			0x10,	/*Packed G279A*/
			0x01,	/*Unpacked G711A*/
			0x11,	/*Packed G711A*/
			0x41,	/*Unpacked G711A with XOR*/
			0x51,	/*Packed G711A with XOR*/
			0x02,	/*Unpacked G711U*/
			0x12,	/*Packed G711U*/
			0x42,	/*Unpacked G711U with XOR*/
			0x52,	/*Packed G711U with XOR*/
			0x03,	/*Unpacked CVSD*/
			0x13,	/*Packed CVSD*/
			0x04,	/*16 bit signed linear PCM*/
			0x24,	/*16 bit unsigned linear PCM*/
			0x84,	/*16 bit signed linear PCM Bit reversed*/
			0xA4	/*16 bit unsigned linear PCM Bit reversed*/
		};

	return xchVal[opt];
}


//-------------------------------------------------------------------
//
//		PRECONFIGURE OPERATIONS
//
//-------------------------------------------------------------------

uint8_t G279A_Encoder_Op(uint32_t nSamples)
{
	uint8_t res;
	uint32_t i = 0;
	uint8_t level = 0;
	uint16_t val = 0;
	uint8_t file_id = 0;
	uint32_t nDataWritten;

	uint16_t bufferIn[INBUFFER_SIZE];
	uint32_t j = 0;

	//DO IT BEFORE
	char filename[] = "g279a_data.dat";
	res = Gui_FileTxtDialogOpen(&file_id, filename, FILE_WRITE, "%d");
	if (res != GUI_FILE_RESULT_OK)
	{
		mprintf("ERROR - Opening file for writing\n");
	}


	Pe0003_CbusWriteWord(CBUSPORT, MODE_REG, 0);				//Idle mode to configure
	Pe0003_CbusWriteWord(CBUSPORT, ANAIN_CONF, 0x0802);			//Power up AnlogIn
	Pe0003_CbusWriteWord(CBUSPORT, ANAIN_COARSE_GAIN, 0);		//0dB gain


	Pe0003_CbusWriteWord(CBUSPORT, FIFO_CONTROL, 0x8080);		//Flush FIFO

	Pe0003_TimerDelayUs(10000);

	Pe0003_CbusWriteWord(CBUSPORT, INPUT_TYPE, INPUT_TYPE_16BIT_SIGNED_PCM);			//16 Bit linear PCM
	Pe0003_CbusWriteWord(CBUSPORT, OUTPUT_TYPE, OUTPUT_TYPE_PACKED_G279A);		//G279 samples

	Pe0003_CbusWriteWord(CBUSPORT, MODE_REG, 0x211);//(MODE_AUDIO_SRC_CBUS << 8) | (MODE_AUDIO_DST_CBUS << 4) | MODE_HALF_TRANSC);			//Analogue input, CBus output


	uint16_t da = Pe0003_CbusReadWord(CBUSPORT, MODE_REG_READBACK);
	if (da > 0)
	{
		mprintf("MODE REG BACCK %d\n", da);
	}


	while(i < nSamples)
	{
		level = Pe0003_CbusReadByte(CBUSPORT, FIFO_OUT_LEVEL);

		//FIXME DANIEL MAYBE WE ARE GETTING THE SAMPLES TOO FAST AFTER READING FIFO LEVEL< IT SHOULD NOT BE AN ISSUE
		//CHECK THIS OUT
		if (level > 0)
		{
			val = Pe0003_CbusReadWord(CBUSPORT, FIFO_OUT_WORD);

			bufferIn[j++] = val;
			i++;

			//Store data in blocks of 10
			if (j == INBUFFER_SIZE)
			{
				j = 0;
				res = Gui_FileTxtWrite(file_id, &bufferIn[0], INBUFFER_SIZE, &nDataWritten, FILE_TYPE_WORD);
				//res = Gui_FileWriteWord(file_id, bufferIn, 10, &nDataWritten);	//FIXME DANIEL BINARY FILE
				//if (res != GUI_FILE_RESULT_OK)
				//{
				//	mprintf("ERROR - Writing data into a file\n");
				//}

			}

			if (DEBUG_DISP)
			{
				if ((i % 255) == 0)
					mprintf("s%d \n", i);
			}
		}

		if (level == WARNING_FIFO_LEVEL)
		{
			mprintf("ERROR - Buffer overflow\n");
		}
	}


	//Store last data
	if (j > 0)
	{
		res = Gui_FileTxtWrite(file_id, &bufferIn[0], j, &nDataWritten, FILE_TYPE_WORD);
		//res = Gui_FileWriteWord(file_id, bufferIn, 10, &nDataWritten);	//FIXME DANIEL BINARY FILE
		//if (res != GUI_FILE_RESULT_OK)
		//{
			//	mprintf("ERROR - Writing data into a file\n");
		//}
	}

	//FIXME DANIEL ADD THE LAST SAMPLES TO THE FILE

	res = Gui_FileClose(file_id);

	mprintf("G279 samples captured\n");

	return TRUE;
}



uint8_t G279A_Decoder_Op(uint32_t nSamples)
{
	uint8_t res;
	uint8_t level = 0;
	uint8_t file_id = 0;
	uint32_t nDataRead;
	uint16_t nstatus = 0;
	uint32_t count = 0;
	uint32_t dispCount = 0;

	uint16_t bufferOut[OUTBUFFER_SIZE];
	uint32_t j = 0;

	//DO IT BEFORE
	char filename[] = "g279a_data.dat";
	res = Gui_FileTxtDialogOpen(&file_id, filename, FILE_READ, "%d");
	if (res != GUI_FILE_RESULT_OK)
	{
		mprintf("ERROR - Opening file for writing\n");
	}


	Pe0003_CbusWriteWord(CBUSPORT, MODE_REG, 0);				//Idle mode to configure
	Pe0003_CbusWriteWord(CBUSPORT, FIFO_CONTROL, 0x8080);		//Flush FIFO

	Pe0003_TimerDelayUs(10000);

	Pe0003_CbusWriteWord(CBUSPORT, INPUT_TYPE, INPUT_TYPE_PACKED_G279A);			//G279 samples
	Pe0003_CbusWriteWord(CBUSPORT, OUTPUT_TYPE, OUTPUT_TYPE_16BIT_SIGNED_PCM);		//PCM 16 bit signed linear

	Pe0003_CbusWriteWord(CBUSPORT, ANAOUT_CONF, ANAOUT_DAC_PWR | ANAOUT_DRVPWR);	//0x802 power up ANAOUT driver
	Pe0003_CbusWriteWord(CBUSPORT, ANAOUT_COARSE_GAIN, 0);							//0dB gain

	Pe0003_CbusWriteWord(CBUSPORT, REG_DONE_SELECT, REG_DONE_MODE);					//Set interrupt on Mode Reg Done
	Pe0003_CbusWriteWord(CBUSPORT, MODE_REG, 0);				//Idle mode to configure
	//FIXME DANIEL SET INTERRUPT

	Pe0003_CbusWriteWord(CBUSPORT, MODE_REG, 0x121);//(MODE_AUDIO_SRC_CBUS << 8) | (MODE_AUDIO_DST_ANA << 4) | MODE_HALF_TRANSC);


	//Previously get some data
	res = Gui_FileTxtRead(file_id, (uint8_t *)bufferOut, OUTBUFFER_SIZE , &nDataRead, FILE_TYPE_WORD);

	//Normal process
	while(nDataRead != 0)
	{

		while(nDataRead != 0)
		{
			level = Pe0003_CbusReadByte(CBUSPORT, FIFO_IN_LEVEL);

			if (level < MAX_FIFO_SIZE)
			{
				if ((MAX_FIFO_SIZE - level) > nDataRead)
				{
					Pe0003_CbusReadWstream(CBUSPORT,  FIFO_IN_WORD, &bufferOut[j], nDataRead);//&bufferOut[j], nDataRead);		//Stream data into the buffer
					count += nDataRead;
					j = 0;
					nDataRead = 0;
				}
				else
				{
					uint8_t spaceLeft = MAX_FIFO_SIZE - level;
					Pe0003_CbusReadWstream(CBUSPORT,  FIFO_IN_WORD, &bufferOut[j], spaceLeft);		//Stream part of the data into the buffer
					j = spaceLeft;
					count += spaceLeft;
					nDataRead -= spaceLeft;
				}
			}

			nstatus = Pe0003_CbusReadWord(CBUSPORT, STATUS);

			if (nstatus & (1 << 11))			//Check for underflow
			{
				mprintf("ERROR - Data underflow\n");
			}

			if (DEBUG_DISP)
			{
				if (count > dispCount)
				{
					dispCount += 255;
					mprintf("s%d \n", count);
				}
			}
		}

		res = Gui_FileTxtRead(file_id, (uint8_t *)bufferOut, OUTBUFFER_SIZE, &nDataRead, FILE_TYPE_WORD);
		if (res != GUI_FILE_RESULT_OK)
		{
			mprintf("ERROR - Reading data from file\n");
		}
	}


	res = Gui_FileClose(file_id);

	mprintf("G279 samples sent\n");

	return TRUE;
}

















//--------------------------------------------------------------------------CUSTOM OPERATION

uint8_t CheckFileOutputRequired()
{
	uint8_t res = FALSE;
	uint8_t modeSrc = MODE_AUDIO_DST_VAL;

	switch(modeSrc)
	{
		case(MODE_AUDIO_DST_CBUS): res = TRUE; break;
		default: res = FALSE;
	}

	return res;
}

uint8_t RunFileOuputRequired(uint8_t *file_id)
{
	uint8_t res = TRUE;

	char filename[] = "test.dat";
	res = Gui_FileTxtDialogOpen(file_id, filename, FILE_WRITE, "%d");
	if (res != GUI_FILE_RESULT_OK)
	{
		mprintf("ERROR - Opening file for writing\n");
		res = FALSE;
	}

	return res;
}


uint8_t RunCBusInAnaOutOp(uint8_t *file_id, uint32_t nSamples)
{
	uint8_t res = FALSE;
	uint32_t nDataWritten;
	uint32_t i = 0;
	uint8_t level = 0;
	uint16_t val = 0;
	uint16_t bufferIn[INBUFFER_SIZE];
	uint32_t j = 0;

	while(i < nSamples)
	{
		level = Pe0003_CbusReadByte(CBUSPORT, FIFO_OUT_LEVEL);

		//FIXME DANIEL MAYBE WE ARE GETTING THE SAMPLES TOO FAST AFTER READING FIFO LEVEL< IT SHOULD NOT BE AN ISSUE
		//CHECK THIS OUT
		if (level > 0)
		{
			val = Pe0003_CbusReadWord(CBUSPORT, FIFO_OUT_WORD);

			bufferIn[j++] = val;
			i++;

			//Store data in blocks of 10
			if (j == INBUFFER_SIZE)
			{
				j = 0;
				res = Gui_FileTxtWrite(*file_id, &bufferIn[0], INBUFFER_SIZE, &nDataWritten, FILE_TYPE_WORD);
				//res = Gui_FileWriteWord(file_id, bufferIn, 10, &nDataWritten);	//FIXME DANIEL BINARY FILE
				//if (res != GUI_FILE_RESULT_OK)
				//{
				//	mprintf("ERROR - Writing data into a file\n");
				//}

			}

			if (DEBUG_DISP)
			{
				if ((i % 1000) == 0)
					mprintf("s%d \n", i);
			}
		}

		if (level == WARNING_FIFO_LEVEL)
		{
			mprintf("ERROR - Buffer overflow\n");
		}
	}


	//Store last data
	if (j > 0)
	{
		res = Gui_FileTxtWrite(*file_id, &bufferIn[0], j, &nDataWritten, FILE_TYPE_WORD);
		//res = Gui_FileWriteWord(file_id, bufferIn, 10, &nDataWritten);	//FIXME DANIEL BINARY FILE
		//if (res != GUI_FILE_RESULT_OK)
		//{
			//	mprintf("ERROR - Writing data into a file\n");
		//}
	}

	return TRUE;
}


uint8_t EndCBusInOp(uint8_t *file_id)
{
	Gui_FileClose(*file_id);

	mprintf("End capture\n");

	return TRUE;
}



uint8_t Custom_Op(uint32_t nSamples)
{
	uint8_t res;
	uint8_t file_id = 0;




	uint8_t enableFileOutput = FALSE;

	//File Output if required
	enableFileOutput = CheckFileOutputRequired();
	if (enableFileOutput)
		RunFileOuputRequired(&file_id);



	//General Configuration
	Pe0003_CbusWriteWord(CBUSPORT, MODE_REG, 0);				//Idle mode to configure
	//FIXME DANIEL ADD THESE SWITCHES
	Pe0003_CbusWriteWord(CBUSPORT, ANAIN_CONF, 0x0802);			//Power up AnlogIn
	Pe0003_CbusWriteWord(CBUSPORT, ANAIN_COARSE_GAIN, 0);		//0dB gain

	Pe0003_CbusWriteWord(CBUSPORT, FIFO_CONTROL, 0x8080);		//Flush FIFO

	Pe0003_TimerDelayUs(10000);

	Pe0003_CbusWriteWord(CBUSPORT, INPUT_TYPE, INPUT_TYPE_VAL | INPUT_RATE_VAL);			//Set input register
	Pe0003_CbusWriteWord(CBUSPORT, OUTPUT_TYPE, OUTPUT_TYPE_VAL | OUTPUT_RATE_VAL);		//Set output register

	Pe0003_CbusWriteWord(CBUSPORT, MODE_REG, (MODE_AUDIO_SRC_VAL << 8) | (MODE_AUDIO_DST_VAL << 4) | MODE_TYPE_VAL);			//Mode register


	//FIXME DANIEL BORRAR
	uint16_t da = Pe0003_CbusReadWord(CBUSPORT, MODE_REG_READBACK);
	if (da > 0)
	{
		nSamples =10000;
		mprintf("MODE REG BACCK %d\n", da);
	}


	//Run main loop
	RunCBusInAnaOutOp(&file_id, nSamples);

	EndCBusInOp(&file_id);

	return TRUE;
}

