/**
 * \file
 *
 * SAM4E ASF Cpp Project with all the drivers to supports SAMTFT4.0_Touch Board
 * from www.ledoelectronics.com
 * Device USB CDC Stack (ext library)
 * CAN Bus
 * TWI, SPI, Usart
 * NT35510 TFT Cpp library
 * Resistive Touch Pad (AD7843)
 * Etcs.
 *
 */

#include "main.h"

//Timer/Counter 0 channel 0
void TC0_Handler(void)
{
	//Read TC Status (required to reset this interrupt)
	uint32_t status;
	status = TC0->TC_CHANNEL[0].TC_SR;
	//If compare match
	if((status & TC_SR_CPCS) == TC_SR_CPCS)
	{
		if(sysLED_counter++>=10)
		{
			sysLED_counter = 0;
			Flags.sys_led_toogle = true;
		}
		
		if(CAN_counter++>=10)
		{
			CAN_counter = 0;
			Flags.CAN_cycle = true;
		}
		
	}
}

void PIOA_Handler(void)
{
	int32_t status;
	status = PIOA->PIO_ISR;
}

/**
 * \brief Interrupt handler for USART.
 * 
 */
void USART0_Handler(void)
{
	uint32_t ul_status;

	/* Read USART Status. */
	ul_status = USART0->US_CSR;//usart_get_status(USART0);
	
	/* Read character. */
	if (ul_status & US_CSR_RXRDY) 
	{
		RS4.rs4_rxbuffer[RS4.rs4_rx_index] = USART0->US_RHR & 0xFF;
		RS4.rs4_rx_index++;
		if(RS4.rs4_rx_index >= RS4_RXBUFFER_LENGHT)
		{
			RS4.rs4_rx_index = 0;
			RS4.rs4_datos_listos = true;
		}
	}
	
	if((ul_status & US_CSR_RXBUFF) )
	{
		//usart_reset_rx(USART0);
	}
	
	if((ul_status & US_CSR_OVRE) )
	{
		//usart_reset_rx(USART0);
		//usart_reset_status(USART0);
	}
	
}


/**
 * \brief Default interrupt handler for CAN 0.
 */
void CAN0_Handler(void)
{
	uint32_t ul_status;
	
    if ( CAN0->CAN_SR & 2)//if data received from CAN_IO_BOARD
    {
	    ul_status = myCan.can_mailbox_get_status(CAN0, 1);
	    if(ul_status & CAN_MSR_MRDY)
	    {
		    myCanAppl.io_rx_mailbox.ul_status = ul_status;
		    myCan.can_mailbox_read(CAN0, &myCanAppl.io_rx_mailbox);
		    myCanAppl.decode_can_msg_IO();
	    }
    }
	
    if ( CAN0->CAN_SR & 8)//if data received from WAGO
    {
	    ul_status = myCan.can_mailbox_get_status(CAN0, 3);
	    if(ul_status & CAN_MSR_MRDY)
	    {
		    myCanAppl.wago_rx_mailbox.ul_status = ul_status;
		    myCan.can_mailbox_read(CAN0, &myCanAppl.wago_rx_mailbox);
		    myCanAppl.decode_can_msg_WAGO();
	    }
    }
	
   

	if ( CAN0->CAN_SR & 32)//if data received from CAN_MOTOR_BOARD
	{
		ul_status = myCan.can_mailbox_get_status(CAN0, 5);
		if(ul_status & CAN_MSR_MRDY)
		{
			myCanAppl.motor_rx_mailbox.ul_status = ul_status;
		    myCan.can_mailbox_read(CAN0, &myCanAppl.motor_rx_mailbox);
		    myCanAppl.decode_can_msg_motor();
		}
	}

	
}

int main (void)
{
	/* Insert system clock initialization code here (sysclk_init()). */
    /* Initialize the SAM system */
    SystemInit();
	Board_init();
	WDT->WDT_MR = WDT_MR_WDDIS;
	Spi0.spi_master_init(SPI,48000000);
	M41t00.twi0_init_m41t00();
	Display.Tft_Init();
	Timers.tc0_init();
   // myCanAppl.Can_initialize();
	Usb_init();
	//Leemos los parametros guardados en flash
	memcpy(ul_page_buffer, (const void *)(DATA_PAGE_ADDRESS ), IFLASH_PAGE_SIZE / sizeof(uint32_t));
	read_params_from_flash_buffer();
	if(params.memory_blank != 1)
	Set_defaults();
	///if(Touch.TCIsPenOn())
	  ///Touch.tp_calibration();
	///Gui.drawBitmap_from_w25q(0,0,800,480,0,1);
	///while(!TOUCH_PRESSED());
	Display.Tft_Clear(YELLOW);
	Gui.setFont(font8x12);
	Gui.print("Test 8x12",20,20,0,VGA_BLUE,YELLOW);
	Gui.setFont(font16x16);
	Gui.print("Test 16x16",300,20,0,VGA_BLUE,YELLOW);
	Gui.setFont(font48);
	Gui.print("Test 48",20,60,0,VGA_GREEN,YELLOW);
    Gui.setFont(font7seg);
    Gui.print("1234567890",20,140,0,VGA_SILVER,YELLOW);	
	Gui.setFont(font7_96_144);
	Gui.print("01796",10,250,0,RED,YELLOW);
    Gui.drawCircle(600,240,WHITE,50,1);
	Gui.drawCircle(600,240,VGA_BLUE,50,0);
	Gui.drawCircle(600,240,VGA_BLUE,80,0);
	Gui.drawRectangle(500,100,700,400,RED);
	Gui.drawTriangle(500,400,600,100,700,400, VGA_BLUE);
	Gui.drawTriangle(501,399,599,99,699,399, VGA_BLUE);
	//Gui.setFont(font48);
	//Gui.print("Primer texto",20,20,0,WHITE,BLUE);
	while(1)
	{
		if(Flags.sys_led_toogle)
		{
			Flags.sys_led_toogle = false;
			Puerto.toggle_pin(PIOD,31);
			//if(!Flags.bitmap)
			  //dateTime_show();
		}
		
		
		if(Flags.CAN_cycle & !Flags.bitmap)
		{
			Flags.CAN_cycle = false;
			myCanAppl.CAN_Loop();
		}
		
		
		if(Usb_data_received())
		{
			usb_msg_decode();
			usb_tx_to_pc();
		}
		
		
	}
	
	
}


void Board_init()
{
	/* Initialize IOPORTs */
    Puerto.PeripheralClock_enable(PIOA);
    Puerto.PeripheralClock_enable(PIOB);
    Puerto.PeripheralClock_enable(PIOD);
	
	//System Led
	Puerto.pin_set_output(PIOD,SYS_LED_MASK,0,0,0);
	
	/** Rotary Encoder. */
	//CanalA
	Puerto.pin_set_input(PIOA,PIO_PA22,PIO_INPUT);
	//CanalB
	Puerto.pin_set_input(PIOA,PIO_PA23,PIO_INPUT);
	//Push Button
	Puerto.pin_set_input(PIOA,PIO_PA24,PIO_PULLUP|PIO_DEBOUNCE);
	//Configure debounce filter at 25Hz
	Puerto.pin_set_debounce_filter(PIOA, PIO_PA24, 25);
	//Configure External Interrupt on fall edge of PIO_PA22 (ENC A)
	Puerto.configure_interrupt(PIOA, PIO_PA22, PIO_IT_FALL_EDGE);
	//Enable external interrupt
	Puerto.enable_pin_interrupt(PIOA,22);
	//Configure Ext Interrupt in NVIC
	Puerto.NVIC_handler_register(PIOA,PIOA_IRQn,1);
	
	//VBUS Pin
	//ioport_set_pin_peripheral_mode(PIO_PB12_IDX, USB_VBUS_FLAGS);
	
	//AD7843 Control PINS
    //cs pin
    Puerto.pin_set_output(PIOD,(1<<24),1,0,0);
    //miso Pin
    Puerto.pin_set_input(PIOD,(1<<27),PIO_INPUT);
    //mosi Pin
    Puerto.pin_set_output(PIOD,(1<<26),1,0,0);
    //spck Pin Pin
    Puerto.pin_set_output(PIOD,(1<<25),1,0,0);
    //AD7843 TP_PEN PIN
    Puerto.pin_set_input(PIOD,(1<<29),PIO_PULLUP);
	//Pin de proteccion de la memoria flash serie
	Puerto.pin_set_output(PIOA,WB_P_PIN_MASK,0,0,0); // WB_P
	
	//Digital Out Pins
	Puerto.pin_set_output(PIOA,OUT0_PIN_MASK,0,0,0);
	Puerto.pin_set_output(PIOA,OUT1_PIN_MASK,0,0,0);
	Puerto.pin_set_output(PIOA,OUT2_PIN_MASK,0,0,0);

	
	// RS485 DE Bus Control Signal
	Puerto.pin_set_output(PIOA,RS4_DE_PIN_MASK,0,0,0);
	
	//PWM Pins
	Puerto.pin_set_peripheral(PIOA, PIO_PERIPH_A, PIO_PA16C_PWML2);
	Puerto.pin_set_peripheral(PIOA, PIO_PERIPH_A, PIO_PA25B_PWMH2);
	
	
	/* ADC Pins. Disable pull-up*/
	PIOA->PIO_SODR = PIO_SODR_P17;
	PIOA->PIO_SODR = PIO_SODR_P18;
	PIOA->PIO_SODR = PIO_SODR_P19;
	PIOA->PIO_SODR = PIO_SODR_P20;
	PIOA->PIO_SODR = PIO_SODR_P21;
	
	//Pin DAC0
	Puerto.pin_set_peripheral(PIOB, PIO_PERIPH_D, PIO_PB13X1_DAC0);
	
	//Allow TWI to control PA3 and PA4
	Puerto.pin_set_peripheral(PIOA, PIO_PERIPH_A, PIO_PA3A_TWD0 | PIO_PA4A_TWCK0);
	
	//Allow USART0 to control PB0 and PB1
	Puerto.pin_set_peripheral(PIOB, PIO_PERIPH_C, PIO_PB0C_RXD0 | PIO_PB1C_TXD0);
	
	//Pines CAN0
	Puerto.pin_set_peripheral(PIOB, PIO_PERIPH_A, PIO_PB3A_CANRX0);
	Puerto.pin_set_peripheral(PIOB, PIO_PERIPH_A, PIO_PB2A_CANTX0);
	
	//Pines de control del display TFT
	Puerto.pin_set_output(PIOD,DB0_PIN_MASK,0,0,0); // DB0
	Puerto.pin_set_output(PIOD,DB1_PIN_MASK,0,0,0); // DB1
	Puerto.pin_set_output(PIOD,DB2_PIN_MASK,0,0,0); // DB2
	Puerto.pin_set_output(PIOD,DB3_PIN_MASK,0,0,0); // DB3
	Puerto.pin_set_output(PIOD,DB4_PIN_MASK,0,0,0); // DB4
	Puerto.pin_set_output(PIOD,DB5_PIN_MASK,0,0,0); // DB5
	Puerto.pin_set_output(PIOD,DB6_PIN_MASK,0,0,0); // DB6
	Puerto.pin_set_output(PIOD,DB7_PIN_MASK,0,0,0); // DB7
	Puerto.pin_set_output(PIOD,DB8_PIN_MASK,0,0,0); // DB8
	Puerto.pin_set_output(PIOD,DB9_PIN_MASK,0,0,0); // DB9
	Puerto.pin_set_output(PIOD,DB10_PIN_MASK,0,0,0); // DB10
	Puerto.pin_set_output(PIOD,DB11_PIN_MASK,0,0,0); // DB11
	Puerto.pin_set_output(PIOD,DB12_PIN_MASK,0,0,0); // DB12
	Puerto.pin_set_output(PIOD,DB13_PIN_MASK,0,0,0); // DB13
	Puerto.pin_set_output(PIOD,DB14_PIN_MASK,0,0,0); // DB14
	Puerto.pin_set_output(PIOD,DB15_PIN_MASK,0,0,0); // DB15
	Puerto.pin_set_output(PIOD,DB16_PIN_MASK,0,0,0); // DB16
	Puerto.pin_set_output(PIOD,DB17_PIN_MASK,0,0,0); // DB17
	Puerto.pin_set_output(PIOD,TFT_RD_PIN_MASK,1,0,0); // RD
	Puerto.pin_set_output(PIOD,TFT_WR_PIN_MASK,1,0,0); // WR
	Puerto.pin_set_output(PIOD,TFT_DC_PIN_MASK,1,0,0); // DC
	Puerto.pin_set_output(PIOD,TFT_CS_PIN_MASK,1,0,0); // CS
	Puerto.pin_set_output(PIOD,TFT_RST_PIN_MASK,1,0,0); // RST
	Puerto.pin_set_output(PIOD,TFT_BKL_PIN_MASK,1,0,0); // BKL
	//Puerto.pin_set_output(PIOD,TFT_IM0_PIN_MASK,1,0,0); // IM0
	//Puerto.pin_set_output(PIOD,TFT_IM1_PIN_MASK,0,0,0); // IM1

	//Habilitamos control del bus de datos
	PIOD->PIO_OWER = 0xFFFF;
	
}


void usb_msg_decode(void)
{
	uint16_t ivalue;

	// Create union of shared memory space
	union {
		float float_var;
		uint8_t temp_array[4];
	} u;
	
	switch(*Usb_rx_data_pointer0())
	{
	   case 1://external flash prog
	   Flags.bitmap = true;
	   address = ((uint32_t)(*(Usb_rx_data_pointer0() + 1))<<16) |
	   ((uint16_t) (*(Usb_rx_data_pointer0() + 2))<<8) | *(Usb_rx_data_pointer0() + 3);
	   page = ((uint32_t)(*(Usb_rx_data_pointer0() + 4))<<8) | *(Usb_rx_data_pointer0() + 5);
	   for(int i=0;i<64;i++)
	   {
		   W25q.u.temp_buffer[i] =  *(Usb_rx_data_pointer1() + i);
		   W25q.u.temp_buffer[i+64] =  *(Usb_rx_data_pointer2() + i);
		   W25q.u.temp_buffer[i+128] =  *(Usb_rx_data_pointer3() + i);
		   W25q.u.temp_buffer[i+192] =  *(Usb_rx_data_pointer4() + i);
	   }
	   W25q.IO_Write_nBytes(address + (page << 8),256);
	 
	   Usb_tx_buffer_fill(0,page % 256);
	   Usb_tx_buffer_fill(1,page>>8);
	   Usb_tx_buffer_fill(2,page>>16);
	   Gui.setFont(font16x16);
	   Gui.printNumI(page, 20, 300,4,'0',VGA_BLUE, VGA_WHITE);
	   Gui.printNumI(address, 20, 360,6,'0',VGA_BLUE, VGA_WHITE);
	   break;
	   case 2://external flash erase
	   W25q.IO_Erase_Chip();
	   W25q.IO_Erase_Chip();
	   break;
	   case 3://mostrar bitmap
	   address = ((uint32_t)(*(Usb_rx_data_pointer0() + 1))<<16) |
	   ((uint32_t) (*(Usb_rx_data_pointer0() + 2))<<8) | *(Usb_rx_data_pointer0() + 3);
	   x = ((uint16_t)(*(Usb_rx_data_pointer0() + 4))<<8) | *(Usb_rx_data_pointer0() + 5);
	   y = ((uint16_t)(*(Usb_rx_data_pointer0() + 6))<<8) | *(Usb_rx_data_pointer0() + 7);
	   ancho = ((uint16_t)(*(Usb_rx_data_pointer0() + 8))<<8) | *(Usb_rx_data_pointer0() + 9);
	   alto = ((uint16_t)(*(Usb_rx_data_pointer0() + 10))<<8) | *(Usb_rx_data_pointer0() + 11);
	   Gui.drawBitmap_from_w25q(x,y,ancho,alto,address,1);
	   break;
	   case 4: //sector 4k erase
	   address = ((uint32_t)(*(Usb_rx_data_pointer0() + 1))<<16) |
	   ((uint16_t) (*(Usb_rx_data_pointer0() + 2))<<8) | *(Usb_rx_data_pointer0() + 3);
	   W25q.IO_Erase_Sector(address);
	   break;
	   case 5: //Block32k erase
	   address = ((uint32_t)(*(Usb_rx_data_pointer0() + 1))<<16) |
	   ((uint16_t) (*(Usb_rx_data_pointer0() + 2))<<8) | *(Usb_rx_data_pointer0() + 3);
	   W25q.IO_Erase_Block32(address);
	   break;
	   case 6: //Block64k erase
	   address = ((uint32_t)(*(Usb_rx_data_pointer0() + 1))<<16) |
	   ((uint16_t) (*(Usb_rx_data_pointer0() + 2))<<8) | *(Usb_rx_data_pointer0() + 3);
	   W25q.IO_Erase_Block64(address);
	   break;
	   case 7:
	   Display.Tft_Clear(BLACK);
	   break;
	   case 150:
	   SAMBA_reboot();
	   break;
	  case 251:
	  memcpy(ul_page_buffer, (const void *)(DATA_PAGE_ADDRESS ), IFLASH_PAGE_SIZE / sizeof(uint32_t));
	  break;
	  case 252:
		//read_params_from_flash_buffer();
	  break;
	  default:
	  break;
		
		

	}
	*Usb_rx_data_pointer0() = 0;//para no repetir comando
}

void usb_tx_to_pc()
{
	unsigned char * p;
	Usb_tx_buffer_fill(4,4);//board type
	chksum_insert();
	Usb_send_report();
	
}

void dateTime_show(void)
{
	M41t00.twi_read_rtc();
	Gui.setFont(font7seg);
	Gui.printNumI(M41t00.decoded_time.hour, 20, 60,2,'0',VGA_BLUE, VGA_WHITE);
	Gui.setFont(font48);
	Gui.printChar(':', 100, 60,VGA_BLUE, VGA_WHITE);
	Gui.setFont(font7seg);
	Gui.printNumI(M41t00.decoded_time.min, 180, 60,2,'0',VGA_BLUE, VGA_WHITE);
	Gui.setFont(font48);
	Gui.printChar(':', 260, 60,VGA_BLUE, VGA_WHITE);
	Gui.setFont(font7seg);
    Gui.printNumI(M41t00.decoded_time.sec, 340, 60,2,'0',VGA_BLUE, VGA_WHITE);
}

void read_params_from_flash_buffer(void)
{
	// Create union of shared memory space
	union {
		float float_variable;
		uint32_t data32;
	} u;
	
	params.memory_blank = ul_page_buffer[0];
	Touch.Points[0].ad7843_val_X = (int16_t) ul_page_buffer[1];
	Touch.Points[0].ad7843_val_Y = (int16_t)ul_page_buffer[2];
	Touch.Points[0].pixel_X = (int16_t)ul_page_buffer[3];
	Touch.Points[0].pixel_Y = (int16_t)ul_page_buffer[4];
	Touch.Points[1].ad7843_val_X = (int16_t) ul_page_buffer[5];
	Touch.Points[1].ad7843_val_Y = (int16_t)ul_page_buffer[6];
	Touch.Points[1].pixel_X = (int16_t)ul_page_buffer[7];
	Touch.Points[1].pixel_Y = (int16_t)ul_page_buffer[8];
	

	//u.data32 = ul_page_buffer[15];
	//params.K_cal = u.float_variable;

}

void Set_defaults(void)
{
	Touch.Points[0].ad7843_val_X = 1700;
	Touch.Points[0].ad7843_val_Y = 30080;
	Touch.Points[0].pixel_X = 5;
	Touch.Points[0].pixel_Y = 5;
	Touch.Points[1].ad7843_val_X = 31128;
	Touch.Points[1].ad7843_val_Y = 1600;
	Touch.Points[1].pixel_X = 795;
	Touch.Points[1].pixel_Y = 475;
	
	save_params_to_flash();
}

void save_params_to_flash(void)
{
	// Create union of shared memory space
	union {
		float float_variable;
		uint32_t data32;
	} u;
	
	ul_page_buffer[0] = 1;
	ul_page_buffer[1] = Touch.Points[0].ad7843_val_X;
	ul_page_buffer[2] = Touch.Points[0].ad7843_val_Y;
	ul_page_buffer[3] = Touch.Points[0].pixel_X;
	ul_page_buffer[4] = Touch.Points[0].pixel_Y;
	ul_page_buffer[5] = Touch.Points[1].ad7843_val_X;
	ul_page_buffer[6] = Touch.Points[1].ad7843_val_Y;
	ul_page_buffer[7] = Touch.Points[1].pixel_X;
	ul_page_buffer[8] = Touch.Points[1].pixel_Y;
	
	
	//u.float_variable = params.K_cal;
	//ul_page_buffer[15] = u.data32;

	flash_init(FLASH_ACCESS_MODE_128, 6);
	/* Unlock page */
	//printf("-I- Unlocking test page: 0x%08x\r\n", ul_test_page_addr);
	flash_unlock(DATA_PAGE_ADDRESS,DATA_PAGE_ADDRESS + IFLASH_PAGE_SIZE - 1, 0, 0);
	/* Write page */
	flash_erase_sector(DATA_PAGE_ADDRESS);
	flash_write(DATA_PAGE_ADDRESS, ul_page_buffer,IFLASH_PAGE_SIZE, 0);

}



RAMFUNC void SAMBA_reboot (void)
{
	// Wait until Flash is ready
	while(!(EFC->EEFC_FSR & EEFC_FSR_FRDY));
	
	//Send Clear GPNVM bit command with argument 1 (Clear GPNVM1)
	EFC->EEFC_FCR = (EEFC_FCR_FKEY_PASSWD | EEFC_FCR_FCMD_CGPB |(1 << EEFC_FCR_FARG_Pos));
	while(!(EFC->EEFC_FSR & EEFC_FSR_FRDY));
	
	// Perform Software reset
	RSTC->RSTC_CR |= ((0xA5u << 24) | RSTC_CR_PROCRST | RSTC_CR_PERRST);
	
	//Infinite loop to avoid further code execution - chip should reset
	while(1);
}


