/**
 * Programa para detector de metales del tipo PI (Pulse Induction)
 * CHIP: AT32UC3C264C  (32 bits)
 * Autor: José Emilio Ledo Galano
 */

#include "main.h"




// Se ejecuta cada vez que se recibe un report por la usb
//udi_callback
void usb_data_received(uint8_t *report)
{
	usb_rx_ptr = &report[0];
	datos_listos = true;
	usb_last_rx_cmd = 0;;
}

void ui_process(uint16_t framenumber)
{

}



void main_sof_action(void)
{
	if (!main_b_generic_enable)
	return;
	//ui_process(udd_get_frame_number());
}




bool main_generic_enable(void)
{
	main_b_generic_enable = true;
	return true;
}

void main_generic_disable(void)
{
	main_b_generic_enable = false;
}

void main_hid_set_feature(uint8_t* report)
{
	;
}


int main (void)
{
	 uint8_t * p;
	 Read_flash_params();
	 if(Params.eep_writed != 1)
	 {
		Set_default(); 
		Read_flash_params(); 
	 }
	 chip_init();
	 strcpy((char *)lcd_buffer_H,"  LEDO GALANO   ");
	 strcpy((char *)lcd_buffer_L,"  METAL FINDER  ");
	 send_to_lcd(1);
	 delay_ms(1200);
     while(1)
	 {
		 
		 if(flags.lcd_menu)
		 {
			 flags.lcd_menu = false;
			 lcd_menu();
		 }

		 
		 if(led_counter>=8)//10
		 {
			 led_counter = 0;
			 //gpio_toggle_pin(LED_0);
			 flags.visualizar = true;
			 
		 }
		 
		 if(adc_sample)
		 {
			 adc_sample = false;
			 //Muestreo_analogicas();
			 
		 }
		 
		 if(datos_listos)
		 {
			 cmd_decode();
			 datos_listos = false;
			 usb_tx();
		 }
		 
        
	 }//end loop

}


void chip_init(void)
{
	 /* System general clock. */
	 sysclk_init();
	 wdt_disable();
	 irq_initialize_vectors();

	 // Initialize interrupt vectors.
	 INTC_init_interrupts();
     cpu_irq_disable();

	 tc0_init(&AVR32_TC0,18000);
	 tc1_init(&AVR32_TC0,500);//26000
	 rs485_init();
	 adc_init(Params.adc_gain);
	 offset = adc_offset();
	 dac_init();
     dac_set_value(200);
	 gpio_configure_pin(LED_0,GPIO_DIR_OUTPUT | GPIO_INIT_HIGH);
	 gpio_configure_pin(LED_1,GPIO_DIR_OUTPUT | GPIO_INIT_HIGH);
	 gpio_configure_pin(LED_2,GPIO_DIR_OUTPUT | GPIO_INIT_HIGH);
	 gpio_configure_pin(LED_3,GPIO_DIR_OUTPUT | GPIO_INIT_HIGH);
	 gpio_configure_pin(LED_4,GPIO_DIR_OUTPUT | GPIO_INIT_HIGH);
	 gpio_configure_pin(PWM,GPIO_DIR_OUTPUT | GPIO_INIT_LOW);
	 gpio_configure_pin(MUTE,GPIO_DIR_OUTPUT | GPIO_INIT_LOW);
	 gpio_configure_pin(MODE_KEY,GPIO_DIR_INPUT | GPIO_PULL_UP);
	 gpio_configure_pin(UP_KEY,GPIO_DIR_INPUT | GPIO_PULL_UP);
	 gpio_configure_pin(OK_KEY,GPIO_DIR_INPUT | GPIO_PULL_UP);
	 gpio_configure_pin(DWN_KEY,GPIO_DIR_INPUT | GPIO_PULL_UP);
	 
	 //external_interrupt_init();
	 //void initEIC();
     //INTC_register_interrupt(&PwmPinChange,AVR32_GPIO_IRQ_5,AVR32_INTC_INT0);
	 
	 udc_start();
	 
	 waves_init();
	 
	 // Enable the interrupts
	 cpu_irq_enable();
	
}




void Muestreo_analogicas(void)
{
	int16_t adc_values[3];
	Read_adc_values(adc_values);
	if(flags.muestrearV)
	{
		adc_V = adc_values[0];// + offset;
		VBuffer[v_buffer_index] = adc_V;
		v_buffer_index++;
		if(v_buffer_index > Params.samples)
		{
		   flags.muestrearV = false;
		   iArea = Area();
		   a_buffer_index++;
		}
	}
	
	
	adc_I = adc_values[1] + ADC_OFFSET_G2;
	IBuffer[i_buffer_index] = adc_I;
	i_buffer_index++;
	if(flags.calcularI)
	{
		flags.calcularI = false;
		I = CalculoI();
	}
	
	adc_ntc = adc_values[2];
}


void LeerV(void)
{
	int16_t adc_values[3];
	Read_adc_values(adc_values);
	adc_V = adc_values[0];// + offset;
	iArea = adc_V;
}





void cmd_decode(void)
{
	switch(*(usb_rx_ptr))
	{
		case 0:
		break;
		case SET_FREQ:
		Params.pwmFreq = *(usb_rx_ptr+1);
		Mosfet_gate_pulse_Off();
		delay_ms(50);
		cpu_irq_disable();
		waves_init();
		cpu_irq_enable();
		break;
		case SET_DUTY:
		Params.pwmDuty = *(usb_rx_ptr+1);
		waves_init();
		//params_save();
		break;
		case SET_MAX_I:
		Params.max_I = *(usb_rx_ptr+2) * 256 + *(usb_rx_ptr+1);
		params_save();
		break;
		case SET_MAX_T:
		Params.max_T = *(usb_rx_ptr+2) * 256 + *(usb_rx_ptr+1);
		//params_save();
		break;
		case SET_DELAY:
		Params.sampleDelay = *(usb_rx_ptr+1);
		waves_init();
		//params_save();
		break;
		case SET_SAMPLES:
		Params.samples = *(usb_rx_ptr+1);
	    //params_save();
		break;
		case SET_VOLUME:
		Params.volume = *(usb_rx_ptr+1);
		//params_save();
		break;
		case SET_ADC_GAIN :
		Params.adc_gain = *(usb_rx_ptr+1);
		adc_init(*(usb_rx_ptr+1));
		adc_offset();
		break;
		case 20:
		dac1_set_value(*(usb_rx_ptr+2) * 256 + *(usb_rx_ptr+1));
		break;
		case 255:
		params_save();
		break;
		default:
		break;
	}
	
	*(usb_rx_ptr) = 0;//borra comando
}




void usb_tx(void)
{
		uint8_t * p;
		int16_t k = 0;
		
		p =(unsigned char *) &adc_ntc;
		ui_hid_report[10]= *p;
		ui_hid_report[11]= *(p+1);
		p =(unsigned char *) &adc_I;
		ui_hid_report[12]= *p;
		ui_hid_report[13]= *(p+1);
		ui_hid_report[14]= Params.pwmFreq;
		ui_hid_report[15]= Params.pwmDuty;
		ui_hid_report[16]= Params.sampleDelay;
		ui_hid_report[17]= Params.samples;
		ui_hid_report[18]= Params.volume;
		p =(unsigned char *) &VBuffer[0];
		ui_hid_report[19]= *p;
		ui_hid_report[20]= *(p+1);
		ui_hid_report[21]= Params.adc_gain;

	    udi_hid_generic_send_report_in(ui_hid_report);
}




/***************************************************************************
*
* Flash User Page Access code
*
****************************************************************************/
#define USER_PAGE_ADDRESS AVR32_FLASHC_USER_PAGE//0x80800000
#define LAST_PAGE_ADDRESS 0x8000FF80
#define SEC_PAGE_USER     0x80800080

void Read_flash_params(void)
{
	cpu_irq_disable();
	int32_t sr = sysreg_read(AVR32_SR);
	memcpy(&Params, (void *)SEC_PAGE_USER, sizeof(Params));
	sysreg_write(AVR32_SR,sr);
	cpu_irq_enable();
}

void Set_default(void)
{
	cpu_irq_disable();
	int32_t sr = sysreg_read(AVR32_SR);
	Params.max_I = 1000;
	Params.max_T = 60;
	Params.pwmDuty = Duty_20;
	Params.pwmFreq = Hz_400;
	Params.sampleDelay = 70; //microsegundos
	Params.samples = 60;
	Params.volume = 90;
	Params.adc_gain = 0;
	Params.eep_writed = 1;
	flashc_memcpy((void *)SEC_PAGE_USER, &Params, sizeof(Params), true);
	sysreg_write(AVR32_SR,sr);
	cpu_irq_enable();
}

void params_save(void)
{
	int32_t sr = sysreg_read(AVR32_SR);
	cpu_irq_disable();
	flashc_memcpy((void *)SEC_PAGE_USER, &Params, sizeof(Params), true);
	sysreg_write(AVR32_SR,sr);
	cpu_irq_enable();
}


int16_t CalculoI(void)
{
	float ftemp;
	int32_t ltemp = 0;
	for(int i=0;i<i_buffer_index;i++)
	 ltemp += (int32_t) IBuffer[i];
	ltemp = ltemp / i_buffer_index;
	ftemp = ADC_REF * (float) ltemp /4096.0F;//V en voltios gainX2
	ftemp *= 10000.0F; //I en mA (R = 0.1 Omh)
	ui_hid_report[22]= i_buffer_index >>8;
	ui_hid_report[23]= i_buffer_index % 256;
	i_buffer_index = 0;

	return (int16_t) ftemp;
}

int16_t Area(void)
{
	int32_t temp = 0;
	for(int i=0;i<Params.samples;i++)
	  temp += VBuffer[i];
	//sprintf(lcd_buffer_L," AREA: %09i",temp);  
	//return temp / 410;  
	return adc_V;
}



void external_interrupt_init(void)
{
	#  define EXT_INT_PWM_PIN_LINE               AVR32_EIC_EXTINT_5_0_PIN
	#  define EXT_INT_PWM_FUNCTION_LINE          AVR32_EIC_EXTINT_5_0_FUNCTION
	#  define EXT_INT_PWM_LINE                    EXT_INT5

	// Structure holding the configuration parameters
	// of the EIC module.
	eic_options_t eic_options;


	// Enable level-triggered interrupt.
	eic_options.eic_mode   = EIC_MODE_EDGE_TRIGGERED;
	// Interrupt will trigger on change.
	eic_options.eic_edge = EIC_EDGE_RISING_EDGE;
	// Enable filter.
	eic_options.eic_filter = EIC_FILTER_ENABLED;
	// For Wake Up mode, initialize in asynchronous mode
	eic_options.eic_async  = EIC_ASYNCH_MODE;
	// Choose External Interrupt Controller Line
	eic_options.eic_line   = EXT_INT_PWM_LINE;


	// Map the interrupt line to the GPIO pin with the right peripheral function.
	gpio_enable_module_pin(EXT_INT_PWM_PIN_LINE, EXT_INT_PWM_FUNCTION_LINE);
	
	// Init the EIC controller with the options
	eic_init(&AVR32_EIC, &eic_options,1);

	// Enable External Interrupt Controller Line
	eic_enable_line(&AVR32_EIC, EXT_INT_PWM_LINE);
	
	
}
















