/**
 * \file
 *
 * \brief Empty user application template
 *
 */

/**
 * \mainpage User Application template doxygen documentation
 *
 * \par Empty user application template
 *
 * Bare minimum empty user application template
 *
 * \par Content
 *
 * -# Include the ASF header files (through asf.h)
 * -# Minimal main function that starts with a call to board_init()
 * -# "Insert application code here" comment
 *
 */

/*
 * Include header files for all drivers that have been imported from
 * Atmel Software Framework (ASF).
 */

#include <asf.h>
#include "diskio.h"
//#include "xitoa.h"
#include "ff.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "led.h"

#include "voltage_analyzer.h"

#define INPUT_OFFSET (2047+197)

//! Temperature sensor calibration data.
static uint16_t tempsense;

void FIFO_init( void);
uint8_t FIFO_add( int16_t value);
int16_t FIFO_remove( void);
int16_t FIFO_get_count( void);
int16_t FIFO_get_at( int16_t position);
void result2str(unsigned char * buffer, int16_t value, uint8_t newline );
void adc_init( void);

#define FIFO_LENGTH (1024)	// FIFO LEN
volatile int16_t FIFO_buff[FIFO_LENGTH]; // FIFO buffer
volatile uint16_t FIFO_read_index;  // index, ze ktereho se bude cist nejprve
volatile uint16_t FIFO_write_index; // index, kam se bude priste zapisovat
uint32_t ttime = 0;
unsigned char fault;
struct calendar_date datum = {
	 .second = 0,
	 .minute = 0,
	 .hour = 0,
	 .date = 5,
	 .month = 5,
	 .year = 2014
};


void FIFO_init( void)
{
	//inicializace promemenych
	FIFO_read_index = 0;
	FIFO_write_index = 0;
}

uint8_t FIFO_add( int16_t value)
{
	FIFO_buff[FIFO_write_index] = value;
	FIFO_write_index++;
	if (FIFO_write_index >= FIFO_LENGTH)
	{ // pokud jsme na konci pole, začneme od začátku
		FIFO_write_index = 0;
	}
	return 0; //OK
}



//uint16_t FIFO_max_block_to_read( void);

int16_t FIFO_remove( void)
{
	int16_t temp;
	cpu_irq_disable();
	temp = FIFO_buff[FIFO_read_index];
	FIFO_read_index++;
	if (FIFO_read_index >= FIFO_LENGTH)
	{
		FIFO_read_index = 0;
	}
	cpu_irq_enable();
	return temp;
}

// budeme brát prvek "aktuální pozice (co jsme naposledy přečetli)-position"
int16_t FIFO_get_at( int16_t position)
{
	int16_t temp;
	int16_t pos;
	
	cpu_irq_disable();
	pos = FIFO_read_index - position - 1;
	if (pos < 0)
	{
		pos =  (FIFO_LENGTH+1) + pos;
	}
	temp = FIFO_buff[pos];
	cpu_irq_enable();
	return temp;
}




int16_t FIFO_get_count( void)
{
	int16_t cnt;
	
	cnt = FIFO_write_index - FIFO_read_index;
	if (cnt < 0) // data jsou pres konec bufferu
	{
		//256 -> 0 az 255
		cnt = (FIFO_LENGTH - FIFO_read_index) + FIFO_write_index;
	}
	
	return cnt;
}
/*
#define FIFO_PREVIOUS_LENGTH (200)	// FIFO LEN
volatile int16_t FIFO_previous_buff[FIFO_PREVIOUS_LENGTH]; // FIFO buffer
volatile uint16_t FIFO_previous_read_index;  // index, ze ktereho se bude cist nejprve
volatile uint16_t FIFO_previous_write_index; // index, kam se bude priste zapisovat

int16_t FIFO_previous_get( void);
int16_t FIFO_previous_get_count( void);
void FIFO_previous_init( void);
int16_t FIFO_previous_add( int16_t data);

void FIFO_previous_init( void)
{
	//inicializace promemenych
	FIFO_previous_read_index = 0;
	FIFO_previous_write_index = 0;
}

int16_t FIFO_previous_add( int16_t data)
{
	FIFO_previous_buff[FIFO_previous_write_index] = data;
	FIFO_previous_write_index++;
	if (FIFO_previous_write_index >= FIFO_PREVIOUS_LENGTH)
	{ // pokud jsme na konci pole, začneme od začátku
		FIFO_previous_write_index = 0;
	}
	return 0; //OK
}

int16_t FIFO_previous_get( void)
{
	int16_t temp;
	//cpu_irq_disable();
	temp = FIFO_previous_buff[FIFO_previous_read_index];
	FIFO_previous_read_index++;
	if (FIFO_previous_read_index >= FIFO_PREVIOUS_LENGTH)
	{
		FIFO_previous_read_index = 0;
	}
	//cpu_irq_enable();
	return temp;
}


int16_t FIFO_previous_get_count( void)
{
	int16_t cnt;
	
	cnt = FIFO_previous_write_index - FIFO_previous_read_index;
	if (cnt < 0) // data jsou pres konec bufferu
	{
		//256 -> 0 az 255
		cnt = (FIFO_PREVIOUS_LENGTH - FIFO_previous_read_index) + FIFO_previous_write_index;
	}
	
	return cnt;
}*/

void result2str(unsigned char * buffer, int16_t value, uint8_t newline )
{
	uint16_t temp;
	if (value < 0)
	{
		buffer[0] = '-';
		temp = -value;
	}
	else
	{
		buffer[0] = ' ';
		temp = value;
	}
	
	buffer[4] = (temp%10)|0b00110000;
	temp /= 10;
	buffer[3] = (temp%10)|0b00110000;
	temp /= 10;
	buffer[2] = (temp%10)|0b00110000;
	temp /= 10;
	buffer[1] = (temp%10)|0b00110000;
	
	if (newline)
	{
			buffer[5] = '\r';
			buffer[6] = '\n';
	}
	else
	{
			buffer[5] = '\t';
			buffer[6] = ' ';
	}

}


static void alarm(uint32_t time)
{
//	uint8_t bcd;

	/* Since the current time will give alarm when rolling over to
	 * next time unit, we just call with that one.
	 * This is safe to here since it's called from a time unit roll
	 * over.
	 */
	rtc_set_alarm(time);

	/*if (time != ttime)
	{	
		LED_Toggle(LED1_YEL_GPIO);
		ttime = time;
	}	*/

	calendar_add_second_to_date(&datum);



}


/**
 * \brief Callback function for ADC interrupts
 *
 * \param adc Pointer to ADC module.
 * \param ch_mask ADC channel mask.
 * \param result Conversion result from ADC channel.
 */
static void adc_handler(ADC_t *adc, uint8_t ch_mask, adc_result_t result)
{
	//ch_mask;
	FIFO_add((int16_t)result);	
	//LED_Toggle(LED1_GPIO); 	
}


void adc_init( void)
{
	struct adc_config         adc_conf;
	struct adc_channel_config adcch_conf;
	
		// Initialize configuration structures.
	adc_read_configuration(&ADCB, &adc_conf);
	adcch_read_configuration(&ADCB, ADC_CH0, &adcch_conf);

	/* Configure the ADC module:
	 * - unsigned, 12-bit results
	 * - bandgap (1 V) voltage reference
	 * - 200 kHz maximum clock rate
	 * - manual conversion triggering
	 * - temperature sensor enabled
	 * - callback function
	 */
	adc_set_conversion_parameters(&adc_conf, ADC_SIGN_OFF, ADC_RES_12, ADC_REF_AREFB); // signed/unsigned ??
	adc_set_clock_rate(&adc_conf, 10000UL);// 10KHz - s rezervou
	adc_set_conversion_trigger(&adc_conf, ADC_TRIG_EVENT_SINGLE, 1, 2);
	//adc_enable_internal_input(&adc_conf, ADC_INT_TEMPSENSE);//-

	adc_write_configuration(&ADCB, &adc_conf);
	adc_set_callback(&ADCB, &adc_handler);
	
	/* Configure ADC channel 0:
	 * - single-ended measurement from temperature sensor
	 * - interrupt flag set on completed conversion
	 * - interrupts disabled
	 */
	adcch_set_input(&adcch_conf, ADCCH_POS_PIN1, ADCCH_NEG_NONE, 1);//1 změny
	adcch_set_interrupt_mode(&adcch_conf, ADCCH_MODE_COMPLETE);
	adcch_enable_interrupt(&adcch_conf);

	adcch_write_configuration(&ADCB, ADC_CH0, &adcch_conf);

	// Get measurement for 85 degrees C (358 kelvin) from calibration data.
	tempsense = adc_get_calibration_data(ADC_CAL_ADCB);

	// Enable the ADC and start the first conversion.
	adc_enable(&ADCB);
	
	//timer setting
	TCC0.CTRLA = 1;
	TCC0.PER = 6399;// =(32000000/5000)-1
	
	// timer event owerflow
	EVSYS.CH2MUX = EVSYS_CHMUX_TCC0_OVF_gc;
	
	//EVSYS.DATA = (1<<2);
	//EVSYS.STROBE = (1<<2);
	
}

FATFS FileSystemObject;
FIL waveFile;
FRESULT FileResult;

int16_t pila = 0;
 
int main(void)
{
	UINT cnt;
	unsigned int i;
	unsigned char buffer[7];
	uint16_t zbyva = 0;
	//nt16_t stoptime = 0;
	//uint16_t counter = 0;

			
		/*for (i = 0; i<100; i++)
		{
			int16_t  out, dist, rms;
			int16_t sample;// = FIFO_get();
			pila += 512;
			if (pila>2047) pila = -2047;
			
			sample = pila ;
			out = filtr3(sample);
			distorsion_rms(sample,out,&dist,&rms);
		}*/

	pmic_init();
	board_init();
	sysclk_init();
	sleepmgr_init();
	rtc_init();
	rtc_set_callback(alarm);	
	
	irq_initialize_vectors();
	cpu_irq_enable();
	
	rtc_set_alarm_relative(0);
	PORTA.DIRSET = 0b111 ;
	LED_On(LED0_RED_GPIO);
	LED_On(LED1_YEL_GPIO);
	LED_On(LED2_GRE_GPIO);

	
	if (disk_initialize(0)!=0)
	{
		//xprintf(PSTR("\nMount mislukt"));
		//LED_On(LED0_GPIO);
		while(1);
		i=0;
	}
	
	if(f_mount(0, &FileSystemObject)!=FR_OK)
	{
		//xprintf(PSTR("\nMount mislukt"));
		//LED_On(LED0_GPIO);
		while(1);
	}
	else
	{
		//xprintf(PSTR("\nMounted..."));
	}
			
	if(f_open(&waveFile, "test.txt",  FA_OPEN_ALWAYS | FA_WRITE )!=FR_OK)
	{
		i=0;
		//LED_On(LED0_GPIO);
		while(1);
	}
	else
	{
		//LED_On(LED2_GPIO);
	}
	
	if (f_lseek(&waveFile,f_size(&waveFile)) != FR_OK )
	{
			i=0;
			//LED_On(LED0_GPIO);
			while(1);
	}
	
	FileResult = f_write(&waveFile,"\r\nNew write\r\n",13,&cnt);
	
	FIFO_init();
	//FIFO_previous_init();
	adc_init();
	
	int16_t test;
	
	while(1)
	{
		if ((test = FIFO_get_count()) > 0)
		{
			//st;
			LED_On(LED2_GRE_GPIO);
			//for (i = 0; i < 128; i++ )
			{
				
				int16_t  out, dist, rms;
				int16_t sample = FIFO_remove()-INPUT_OFFSET;
				
				//pila += 128;
				//if (pila>2047) pila = -2047;
				//sample = pila ;
				
				out = filtr3(sample);
				//FIFO_previous_add(sample);
				distorsion_rms(sample,out,&dist,&rms);
				
				/*if (stoptime>0)
				{
					stoptime--;
				}*/
				
				
				if (zbyva>0)   //když kontrola zjisti chybu, tak se uloží tolik vzorků, dokud neni zase 0
				{
					zbyva--;
					result2str(buffer,sample,0);
					FileResult = f_write(&waveFile,buffer,7,&cnt);
					result2str(buffer,dist,0);
					FileResult = f_write(&waveFile,buffer,7,&cnt);
					result2str(buffer,rms,1);
					FileResult = f_write(&waveFile,buffer,7,&cnt);
					//result2str(buffer,ttime);
					//FileResult = f_write(&waveFile,buffer,7,&cnt);
					if (zbyva == 0)
					{
						f_sync(&waveFile);
						//stoptime = 200;
					}
					
				}
				else
				{
					fault = kontrola(dist, rms);
					//if ((fault != 0) && (stoptime == 0))
					if (fault != 0)
					{
						int16_t j;
						FileResult = f_write(&waveFile,"\r\nChyba\r\n",9,&cnt);
						result2str(buffer,ttime,1);
						FileResult = f_write(&waveFile,buffer,7,&cnt);
						result2str(buffer,fault,1);
						FileResult = f_write(&waveFile,buffer,7,&cnt);
						result2str(buffer,datum.hour,0);
						FileResult = f_write(&waveFile,buffer,7,&cnt);
						result2str(buffer,datum.minute,0);
						FileResult = f_write(&waveFile,buffer,7,&cnt);
						result2str(buffer,datum.second,1);
						FileResult = f_write(&waveFile,buffer,7,&cnt);
						
						FileResult = f_write(&waveFile,"-------\r\n",9,&cnt);
						
						
						for (j = 200; j>0; j--)
						{
							int16_t smp;
							smp = FIFO_get_at(j-1)-INPUT_OFFSET;
							result2str(buffer,smp,1);
							FileResult = f_write(&waveFile,buffer,7,&cnt);
						}
						
						//test = FIFO_previous_get_count();
						//test;
						zbyva = 201;
					}
					
				}
				
			}
			
			LED_Off(LED2_GRE_GPIO);
			
			/*counter++;
			if (counter > 400) // omezení cyklů - zakomentovat
			{
				break;
			}*/
		}
	}
	f_close(&waveFile);
	while(1){
		
		};

}
