/**
 * \file
 *
 * \brief Main functions for Generic example
 *
 * Copyright (c) 2011-2018 Microchip Technology Inc. and its subsidiaries.
 *
 * \asf_license_start
 *
 * \page License
 *
 * Subject to your compliance with these terms, you may use Microchip
 * software and any derivatives exclusively with Microchip products.
 * It is your responsibility to comply with third party license terms applicable
 * to your use of third party software (including open source software) that
 * may accompany Microchip software.
 *
 * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
 * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
 * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
 * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
 * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
 * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
 * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
 * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE.  TO THE FULLEST EXTENT
 * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
 * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
 * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
 *
 * \asf_license_stop
 *
 */
/*
 * Support and FAQ: visit <a href="https://www.microchip.com/support/">Microchip Support</a>
 */

#include <asf.h>
#include "conf_usb.h"
#include "ui.h"
#include <delay.h>
//#define   USB_DEVICE_LOW_SPEED
static volatile bool main_b_generic_enable = false;

///////////////////////////////////////////
// sub func of FLASH access
////////////////////////////////////////////

// set direction for IO port, true -> output, false --> input
void Set_IO_Port_Dir_Out(Bool dir)
{
	if(dir==true)
	{
		ioport_set_pin_dir(IO_7_PIN, IOPORT_DIR_OUTPUT);
		ioport_set_pin_dir(IO_6_PIN, IOPORT_DIR_OUTPUT);
		ioport_set_pin_dir(IO_5_PIN, IOPORT_DIR_OUTPUT);
		ioport_set_pin_dir(IO_4_PIN, IOPORT_DIR_OUTPUT);
		ioport_set_pin_dir(IO_3_PIN, IOPORT_DIR_OUTPUT);
		ioport_set_pin_dir(IO_2_PIN, IOPORT_DIR_OUTPUT);
		ioport_set_pin_dir(IO_1_PIN, IOPORT_DIR_OUTPUT);
		ioport_set_pin_dir(IO_0_PIN, IOPORT_DIR_OUTPUT);
		
		ioport_set_pin_mode(IO_7_PIN, IOPORT_MODE_PULLUP);
		ioport_set_pin_mode(IO_6_PIN, IOPORT_MODE_PULLUP);
		ioport_set_pin_mode(IO_5_PIN, IOPORT_MODE_PULLUP);
		ioport_set_pin_mode(IO_4_PIN, IOPORT_MODE_PULLUP);
		ioport_set_pin_mode(IO_3_PIN, IOPORT_MODE_PULLUP);
		ioport_set_pin_mode(IO_2_PIN, IOPORT_MODE_PULLUP);
		ioport_set_pin_mode(IO_1_PIN, IOPORT_MODE_PULLUP);
		ioport_set_pin_mode(IO_0_PIN, IOPORT_MODE_PULLUP);
	}
	else
	{
		ioport_set_pin_dir(IO_7_PIN, IOPORT_DIR_INPUT);
		ioport_set_pin_dir(IO_6_PIN, IOPORT_DIR_INPUT);
		ioport_set_pin_dir(IO_5_PIN, IOPORT_DIR_INPUT);
		ioport_set_pin_dir(IO_4_PIN, IOPORT_DIR_INPUT);
		ioport_set_pin_dir(IO_3_PIN, IOPORT_DIR_INPUT);
		ioport_set_pin_dir(IO_2_PIN, IOPORT_DIR_INPUT);
		ioport_set_pin_dir(IO_1_PIN, IOPORT_DIR_INPUT);
		ioport_set_pin_dir(IO_0_PIN, IOPORT_DIR_INPUT);
	}
}


uint8_t XA_pin[9];
uint8_t YA_pin[6];
uint8_t IO_pin[8];
uint8_t CE_pin[4];
uint8_t IP_CE_pin[8];

void function_init(void)
{
	XA_pin[0]=XA0_PIN;
	XA_pin[1]=XA1_PIN;
	XA_pin[2]=XA2_PIN;
	XA_pin[3]=XA3_PIN;
	XA_pin[4]=XA4_PIN;
	XA_pin[5]=XA5_PIN;
	XA_pin[6]=XA6_PIN;
	XA_pin[7]=XA7_PIN;
	XA_pin[8]=XA8_PIN;
	
	YA_pin[0]=YA0_PIN;
	YA_pin[1]=YA1_PIN;
	YA_pin[2]=YA2_PIN;
	YA_pin[3]=YA3_PIN;
	YA_pin[4]=YA4_PIN;
	YA_pin[5]=YA5_PIN;

	IO_pin[0]=IO_0_PIN;
	IO_pin[1]=IO_1_PIN;
	IO_pin[2]=IO_2_PIN;
	IO_pin[3]=IO_3_PIN;
	IO_pin[4]=IO_4_PIN;
	IO_pin[5]=IO_5_PIN;
	IO_pin[6]=IO_6_PIN;
	IO_pin[7]=IO_7_PIN;

	CE_pin[0]=CE_1_PIN;
	CE_pin[1]=CE_2_PIN;
	CE_pin[2]=CE_3_PIN;
	CE_pin[3]=CE_4_PIN;

	IP_CE_pin[0]=IP_CE0_PIN;
	IP_CE_pin[1]=IP_CE1_PIN;
	IP_CE_pin[2]=IP_CE2_PIN;
	IP_CE_pin[3]=IP_CE3_PIN;
	IP_CE_pin[4]=IP_CE4_PIN;
	IP_CE_pin[5]=IP_CE5_PIN;
	IP_CE_pin[6]=IP_CE6_PIN;
	IP_CE_pin[7]=IP_CE7_PIN;
}






void Output_8bit(uint8_t data)
{
	uint8_t i;
	Set_IO_Port_Dir_Out(true);
	for(i=0;i<8;i++)
	{
		if(data & (1<<i))
			ioport_set_pin_level(IO_pin[i], IOPORT_PIN_LEVEL_HIGH);
		else
			ioport_set_pin_level(IO_pin[i], IOPORT_PIN_LEVEL_LOW);
	}	
}

uint8_t input_8bit(void)
{
	uint8_t i,u8temp,result;
	result=0;
	Set_IO_Port_Dir_Out(false);
	for(i=0;i<8;i++)
	{
		u8temp=0;
		u8temp = ioport_get_pin_level(IO_pin[i]);
		if(u8temp)	
			result |=1;
		result <<=1;		
	}
	return result;
}

void XA_output(uint16_t xa)
{
	uint16_t i;
	for(i=0;i<9;i++)
	{
		if(xa & (1<<i))
			ioport_set_pin_level(XA_pin[i], IOPORT_PIN_LEVEL_HIGH);
		else
			ioport_set_pin_level(XA_pin[i], IOPORT_PIN_LEVEL_LOW);
	}
}


void YA_output(uint8_t ya)
{
	uint8_t i;
	for(i=0;i<6;i++)
	{
		if(ya & (1<<i))
			ioport_set_pin_level(YA_pin[i], IOPORT_PIN_LEVEL_HIGH);
		else
			ioport_set_pin_level(YA_pin[i], IOPORT_PIN_LEVEL_LOW);
	}
}

// power-on to reset
void PwerOnRst(void)
{
	ioport_set_pin_level(POR_PIN, IOPORT_PIN_LEVEL_LOW);
	
	ALL_CHIP_SET_HIGH;
	
	ioport_set_pin_level(RDEN_PIN, IOPORT_PIN_LEVEL_LOW);
	ioport_set_pin_level(CLOCK_PIN, IOPORT_PIN_LEVEL_LOW);
	ioport_set_pin_level(PROG_PIN, IOPORT_PIN_LEVEL_LOW);
	ioport_set_pin_level(ERASE_PIN, IOPORT_PIN_LEVEL_LOW);
	
	delay_us(1);   // delay Trt 
	
	ioport_set_pin_level(POR_PIN, IOPORT_PIN_LEVEL_HIGH);
	delay_us(42);  // delay Trhr 
	
}

// erase chip selected 
void ChipErase(uint8_t chip , uint8_t Ers_HV)
{
	uint16_t i;
    // all clear
	TC_LATCH_SET_LOW;
	//ALL_CHIP_SET_LOW;
	//IP_CE0_SET_LOW;
	ioport_set_pin_level(IP_CE_pin[0], IOPORT_PIN_LEVEL_LOW);
	//IP_CE1_SET_LOW;
	ioport_set_pin_level(IP_CE_pin[TEST_ESF_IP_IDX], IOPORT_PIN_LEVEL_LOW);
	ERASE_SET_LOW;
	ERASE_1_SET_LOW;
	CONFEN_SET_LOW;
	PLSE_1_PIN_SET_LOW;
	PLSE_2_PIN_SET_LOW;
	TestModeEntry(chip);
	
	TMEN_SET_HIGH;
	WE_SET_LOW;
	for(i=0;i<1000;i++);
	////start op
	if(chip <4)
	{
		ioport_set_pin_level(CE_pin[chip], IOPORT_PIN_LEVEL_HIGH);
	}
	WE_SET_HIGH;
	XA_output(9);
	Set_IO_Port_Dir_Out(true);
	Output_8bit(Ers_HV & 0xF); // variable, should be set by host
	delay_us(1);   //// not mentioned in spec???
	CONFEN_SET_HIGH;
	delay_us(10);   //// not mentioned in spec???
	CONFEN_SET_LOW;
	delay_us(1);   //// not mentioned in spec???
	XA_output(0x16);
	Output_8bit(Ers_HV & (1<<4)); // variable, should be set by host
	delay_us(1); 
	CONFEN_SET_HIGH;
	delay_us(10);   //// not mentioned in spec???
	CONFEN_SET_LOW;
	delay_us(1);   //// not mentioned in spec???
	
	WE_SET_LOW;
	ioport_set_pin_level(CE_pin[chip], IOPORT_PIN_LEVEL_LOW);
   
	YA_output(4);
	Output_8bit(2); 
    /// delay ??? not mentioned
	delay_us(1);
	TC_LATCH_SET_HIGH;
	delay_us(10);
	TC_LATCH_SET_LOW;
	delay_us(10);
	
	ioport_set_pin_level(CE_pin[chip], IOPORT_PIN_LEVEL_HIGH);
	//IP_CE1_SET_HIGH;
	ioport_set_pin_level(IP_CE_pin[TEST_ESF_IP_IDX], IOPORT_PIN_LEVEL_HIGH);
	
	// delay Tws, min=0
	for(i=0;i<100;i++);

	ERASE_SET_HIGH;
	ERASE_1_SET_HIGH;
	delay_us(5); // Tnvs
	
	WE_SET_HIGH;
	delay_ms(9); // Tsce (mark as Tcse in diagram) chip erase time
	WE_SET_LOW;
	PLSE_1_PIN_SET_HIGH;
	delay_us(31); // Teow1
	
	PLSE_1_PIN_SET_LOW;
	ERASE_1_SET_LOW;
	PLSE_2_PIN_SET_HIGH;
	delay_us(11); // Teow2
	
	PLSE_2_PIN_SET_LOW;
	delay_us(15);			// Trcv MIN=50, but includes Teow1 + Teow2 
	ERASE_SET_LOW;
	
	for(i=0;i<100;i++);	//delay Twh( min=0) + Twr (min=100ns)
	ioport_set_pin_level(CE_pin[chip], IOPORT_PIN_LEVEL_LOW);
	//IP_CE1_SET_LOW;
	ioport_set_pin_level(IP_CE_pin[TEST_ESF_IP_IDX], IOPORT_PIN_LEVEL_LOW);
	
	delay_us(10);	//delay Tvph, but not mention detail in spec.
	// test mode exit
	TestModeExit(chip);
}

void SectorErase(uint8_t chip, uint8_t Ers_HV, uint16_t sector, uint8_t num)
{
	uint16_t i,j;
	uint16_t u16temp;
	u16temp = sector & ~(0x3);
	
	ERASE_SET_LOW;
	ERASE_1_SET_LOW;
	CONFEN_SET_LOW;
	PLSE_1_PIN_SET_LOW;
	PLSE_2_PIN_SET_LOW;
	//TC_LATCH_SET_LOW;
	//ALL_CHIP_SET_LOW;
	TestModeEntry(chip);	
	Set_IO_Port_Dir_Out(true);
	TMEN_SET_HIGH;
	WE_SET_LOW;
	
	delay_us(5);

	
	////start op
	if(chip <4)
	{
		ioport_set_pin_level(CE_pin[chip], IOPORT_PIN_LEVEL_HIGH);
	}
	WE_SET_HIGH;
	XA_output(9);
	Output_8bit(Ers_HV & 0xF); // variable, should be set by host
	delay_us(1);   //// not mentioned in spec???
	CONFEN_SET_HIGH;
	delay_us(10);   //// not mentioned in spec???
	CONFEN_SET_LOW;
	delay_us(1);   //// not mentioned in spec???
	XA_output(0x16);
	Output_8bit(Ers_HV & (1<<4)); // variable, should be set by host
	CONFEN_SET_HIGH;
	delay_us(10);   //// not mentioned in spec???
	CONFEN_SET_LOW;
	delay_us(1);   //// not mentioned in spec???
		
	WE_SET_LOW;
	ioport_set_pin_level(CE_pin[chip], IOPORT_PIN_LEVEL_LOW);
	delay_us(10);
	
	for(j=0;j<num;j++)
	{
		
		ioport_set_pin_level(CE_pin[chip], IOPORT_PIN_LEVEL_HIGH);
		//IP_CE1_SET_HIGH;
		ioport_set_pin_level(IP_CE_pin[TEST_ESF_IP_IDX], IOPORT_PIN_LEVEL_HIGH);
		XA_output(u16temp);
		// delay Tws, min=0
		for(i=0;i<10;i++);

		ERASE_SET_HIGH;
		ERASE_1_SET_HIGH;
		delay_us(5); // Tnvs
	
		WE_SET_HIGH;
		delay_ms(9); // Tsce (mark as Tcse in diagram) chip erase time
		WE_SET_LOW;
		PLSE_1_PIN_SET_HIGH;
		delay_us(31); // Teow1
	
		PLSE_1_PIN_SET_LOW;
		ERASE_1_SET_LOW;
		PLSE_2_PIN_SET_HIGH;
		delay_us(11); // Teow2
	
		PLSE_2_PIN_SET_LOW;
		delay_us(15);			// Trcv MIN=50, but includes Teow1 + Teow2
		ERASE_SET_LOW;
	
		for(i=0;i<10;i++);	//delay Twh( min=0) + Twr (min=100ns)
		ioport_set_pin_level(CE_pin[chip], IOPORT_PIN_LEVEL_LOW);
		//IP_CE1_SET_LOW;
		ioport_set_pin_level(IP_CE_pin[TEST_ESF_IP_IDX], IOPORT_PIN_LEVEL_LOW);
		delay_us(10);	//delay Tvph, but not mention detail in spec.	
		
	}
	// test mode exit
	TestModeExit(chip);	
}


void EsfRead(uint8_t chip, uint16_t xa, uint8_t ya, uint16_t length, uint8_t * dst)
{
	uint8_t u8temp;
	uint16_t i,len;
	uint8_t	 y_addr;
	uint16_t x_addr;
	y_addr = ya & 0x3;
	x_addr = xa;
	
	TC_LATCH_SET_LOW;
	TestModeEntry(chip);
	RDEN_SET_LOW;
	STROB0_SET_LOW;
	STROB1_SET_LOW;
	OE_SET_LOW;
	
	delay_us(30);
	YA_output(4);
	Output_8bit(1);
	delay_us(1);
	TC_LATCH_SET_HIGH;
	delay_us(10);
	TC_LATCH_SET_LOW;
	delay_us(1);
	
	Set_IO_Port_Dir_Out(false);
	delay_us(10); 
	ioport_set_pin_level(CE_pin[chip], IOPORT_PIN_LEVEL_HIGH);
	//IP_CE1_SET_HIGH;
	ioport_set_pin_level(IP_CE_pin[TEST_ESF_IP_IDX], IOPORT_PIN_LEVEL_HIGH);
	
	delay_us(50);    // delay tMS, min=50us
	for(len=0;len<length;len++)
	{
		XA_output(x_addr);
		YA_output(y_addr);
		
		delay_us(1);
		RDEN_SET_HIGH;
		delay_us(1);	//delay Tas min=8ns
		CLOCK_SET_HIGH;
		delay_us(10);  // tclkh??  means tckh mentioned? min=8ns
		CLOCK_SET_LOW;
		delay_us(1);   //tah,hold time 2ns
		RDEN_SET_LOW;
		delay_us(1);       //delay tACC min=200ns
		OE_SET_HIGH;
		STROB1_SET_HIGH;
		delay_us(1);   //toe,output enable time min=15ns
		u8temp = input_8bit();
		*(dst+len) = u8temp;
		OE_SET_LOW;
		for(i=0;i<20;i++); // tol, MAX=20ns
		STROB1_SET_LOW;
		
		if(y_addr >= 3)
		{
			y_addr =0;
			x_addr ++;
		}
		else
			y_addr++;
	}
	ioport_set_pin_level(CE_pin[chip], IOPORT_PIN_LEVEL_LOW);
	//IP_CE1_SET_LOW;
	ioport_set_pin_level(IP_CE_pin[TEST_ESF_IP_IDX], IOPORT_PIN_LEVEL_LOW);
	TestModeExit(chip);
}
void TestModeExit(uint8_t chip)
{
	uint16_t i;
	TMEN_SET_HIGH;
	if(chip <4)
		ioport_set_pin_level(CE_pin[chip], IOPORT_PIN_LEVEL_LOW);
	WE_SET_LOW;
	// delay tTWES, but not mentioned, use same as TCS min=8ns
	for(i=0;i<100;i++);
	Output_8bit(0); 
	if(chip <4)
		ioport_set_pin_level(CE_pin[chip], IOPORT_PIN_LEVEL_HIGH);
	delay_us(5);
	TMEN_SET_LOW;
	delay_us(10);
	if(chip <4)
		ioport_set_pin_level(CE_pin[chip], IOPORT_PIN_LEVEL_LOW);
	delay_us(5);  //tTWEH not mentioned???
	WE_SET_HIGH;
	delay_us(10);
}

void TestModeEntry(uint8_t chip)
{
	uint16_t i,j;
	
	WE_SET_LOW;
	TMEN_SET_HIGH;
	ioport_set_pin_level(CE_pin[chip], IOPORT_PIN_LEVEL_LOW);
	// delay tTCS min=5ns?? 50ns
	for(i=0;i<1000;i++);
	WE_SET_HIGH;
	Set_IO_Port_Dir_Out(true);
	XA_output(0x1F);
	Output_8bit(0);
	
	for(j=0;j<3;j++)
	{
		for(i=0;i<1000;i++); // delay tTIS, min=50ns
		TMEN_SET_LOW;
		// delay tTPL, min=20ns
		for(i=0;i<1000;i++);
		TMEN_SET_HIGH;
	
		// delay tTIH, min=50ns
		for(i=0;i<500;i++);
		TMEN_SET_HIGH;
	}
	WE_SET_LOW;
	Set_IO_Port_Dir_Out(false);
	
	// delay tTNXT min=10us,   includes tTCH, min=50ns
	delay_us(11);
}

void Dig_Prog(uint8_t chip, uint8_t PRGDIG_HV,uint8_t ENIP_PRGDIG,uint8_t ENBIAS_PRGDIG, uint32_t * src, uint16_t num,uint16_t xa, uint8_t ya)
{
	uint32_t i,j,k;
	uint32_t u32temp;
	TC_LATCH_SET_LOW;
	CONFEN_SET_LOW;
	ioport_set_pin_level(CE_pin[chip], IOPORT_PIN_LEVEL_LOW);
	WE_SET_LOW;
	PROG_SET_LOW;
	PROG_1_SET_LOW;
	PROG_2_SET_LOW;
	PROG_SET_LOW;
	PLSE_2_PIN_SET_LOW;
	PLSE_1_PIN_SET_LOW;
	//IP_CE1_SET_LOW;
	ioport_set_pin_level(IP_CE_pin[TEST_ESF_IP_IDX], IOPORT_PIN_LEVEL_LOW);
	
	WE_SET_HIGH;
	ioport_set_pin_level(CE_pin[chip], IOPORT_PIN_LEVEL_HIGH);
	for(i=0;i<1000;i++);
	Set_IO_Port_Dir_Out(true);
	
	XA_output(0x0E);
	Output_8bit(PRGDIG_HV & (1<<4));
	delay_us(1);
	CONFEN_SET_HIGH;
	delay_us(10);
	CONFEN_SET_LOW;
	delay_us(1);

	XA_output(0x14);
	Output_8bit(PRGDIG_HV & (0xF));
	delay_us(1);
	CONFEN_SET_HIGH;
	delay_us(10);
	CONFEN_SET_LOW;
	delay_us(1);	
	
	XA_output(0x3);
	Output_8bit(ENIP_PRGDIG);
	delay_us(1);
	CONFEN_SET_HIGH;
	delay_us(10);
	CONFEN_SET_LOW;
	delay_us(1);
	
	XA_output(0x1F);
	Output_8bit(ENBIAS_PRGDIG);
	delay_us(1);
	CONFEN_SET_HIGH;
	delay_us(10);
	CONFEN_SET_LOW;
	delay_us(1);
	
	ioport_set_pin_level(CE_pin[chip], IOPORT_PIN_LEVEL_LOW);
	WE_SET_LOW;
	
	for(j=0;j<num;j++)
	{
		u32temp = *(src + j);
		for(k=0;k<4;k++)
		{
			YA_output(k);
			Output_8bit(u32temp >> (k*8));
			delay_us(1);
			TC_LATCH_SET_HIGH;
			delay_us(10);
			TC_LATCH_SET_LOW;
			delay_us(1);
		}
		ioport_set_pin_level(CE_pin[chip], IOPORT_PIN_LEVEL_HIGH);
		//IP_CE1_SET_HIGH;
		ioport_set_pin_level(IP_CE_pin[TEST_ESF_IP_IDX], IOPORT_PIN_LEVEL_HIGH);
		for(i=0;i<500;i++);
		XA_output(xa);
		YA_output(ya);
		
		for(i=0;i<500;i++);
		PROG_SET_HIGH;
		PROG_1_SET_HIGH;
		delay_us(6);    // tnvs min=4us

		WE_SET_HIGH;
		delay_us(65);  //tpgs  min=60us
		PROG_2_SET_HIGH;
		delay_us(10);  //tprog max= 10us
		PROG_2_SET_LOW;
		delay_us(5);  //tads
		
		delay_us(5);  //tadh
		PROG_2_SET_HIGH;
		delay_us(10);  //tprog max= 10us		
		PROG_2_SET_LOW;
		delay_us(1);  //tpgh  --15ns
		
		//delay tpgs (60) + (tprog(10) + tads (15) + tadh (3)) X2  + tpgh (15) = 120us
		WE_SET_LOW;
		PLSE_1_PIN_SET_HIGH;
		delay_us(31); // Teow1
	
		PLSE_1_PIN_SET_LOW;
		PROG_1_SET_LOW;
		PLSE_2_PIN_SET_HIGH;
		delay_us(11); // Teow2
	
		PLSE_2_PIN_SET_LOW;
		delay_us(15);			// Trcv MIN=50, but includes Teow1 + Teow2
		PROG_SET_LOW;
		delay_us(15);
	}
	ioport_set_pin_level(CE_pin[chip], IOPORT_PIN_LEVEL_LOW);
	//IP_CE1_SET_LOW;
	ioport_set_pin_level(IP_CE_pin[TEST_ESF_IP_IDX], IOPORT_PIN_LEVEL_LOW);
	delay_us(15);
}

/*! \brief Main function. Execution starts here.
 */
// for offline test usage, size of array can be changed



uint8_t u8buf[16]={0};
uint32_t u32buf[32]={0};
	
	///////////////
	// for command method
	// command set parameter first, other op will reduce protocol packet length
	// option 1: dedicated command set parameter, other commands do not include trim parameter
	// option 2: all flash processing commands include trim paratmeter, more flexible
	// now use option 2 for more flexible
	
	uint8_t Ers_HV=ERS_HV_VALUE;
	uint8_t PrgDig_HV=PRGDIG_HV_VALUE;
	uint8_t Enip_PrgDig = ENIP_PRGDIG_VALUE;
	uint8_t Enbias_PrgDig = ENBIAS_PRGDIG_VALUE;
	
	//////////////
int main(void)
{
	uint16_t tick=0;
	uint8_t  u8temp=0;
	irq_initialize_vectors();
	cpu_irq_enable();

	// Initialize the sleep manager
	#ifndef __OFFLINE_RUN_TEST
	sleepmgr_init();
	#endif
	function_init();
	

#if !SAM0
	sysclk_init();
	board_init();
#else
	system_init();
#endif
	ui_init();
	ui_powerdown();
    function_init();
	
	// Test toggle
	
	while(0) {
		TMEN_SET_LOW;
		TMEN_SET_HIGH;
		
		TMEN_SET_LOW;
		TMEN_SET_HIGH;
		
		TMEN_SET_LOW;
		TMEN_SET_HIGH;
		
		TMEN_SET_LOW;
		TMEN_SET_HIGH;
	}
	
	#ifndef __OFFLINE_RUN_TEST
	// Start USB stack to authorize VBus monitoring
	udc_start();
	#endif
	
	Report_send_struct.report_valid=IDLE;
	Report_send_struct.report_len=0;
	
	Cmd_received_struct.cmd_valid=IDLE;
	Cmd_received_struct.data_len=0;
	// The main loop manages only the power mode
	// because the USB management is done by interrupt
	MUX_Select(MCU_IF, ENABLE);
	PwerOnRst();		
	
	while (true) {
#ifdef   USB_DEVICE_LOW_SPEED
		// No USB "Keep a live" interrupt available in low speed
		// to scan generic interface then use main loop
		if (main_b_generic_enable) {
			static volatile uint16_t virtual_sof_sub = 0;
			static uint16_t virtual_sof = 0;
			if (sysclk_get_cpu_hz()/50000 ==
				virtual_sof_sub++) {
				virtual_sof_sub = 0;
				static uint16_t virtual_sof = 0;
				ui_process(virtual_sof++);
			}
		}
#else
		#ifndef __OFFLINE_RUN_TEST
		sleepmgr_enter_sleep();
		#endif
		
		for(;;)
		{
			
			
			#if __TEST_GPIO

						u8temp = ioport_get_pin_level(TEST_GPI);
						if(u8temp !=0)
						{
							LED_On(LED0);
							ioport_set_pin_level(TEST_GPO, IOPORT_PIN_LEVEL_HIGH);
						}
						else
						{
							LED_Off(LED0);
							ioport_set_pin_level(TEST_GPO, IOPORT_PIN_LEVEL_LOW);
						}
			
			#else
					#ifndef __OFFLINE_RUN_TEST
						if(Is_Cmd_Pending())  // valid command received
						{
							cmd_Op(&Cmd_received_struct);
						}
					#else
						///////////////////////////////////////////////////
						//// skip USB, just offline run flash test process 
						//// POR process before processing, then
						//// 1- read 
						//// 2- chip erase
						/////3- read again
						//// 4- program to 0
						//// 5- read again, 0 expected.
						////////////////////////////////////////////////////
						
						/// switch MUX to MCU control, then assert POR process
						    MUX_Select(MCU_IF, ENABLE);
						    PwerOnRst();
							
							///// next to read ESF chip 1, 8bit into buf
							EsfRead(TEST_ESF_IDX, 0, 0, 1, &u8buf[0]);
							
							u8buf[16] =u8buf[0];    // dummy to break here
							u8buf[15] =u8buf[0];    // dummy to break here
							u8buf[14] =u8buf[0];    // dummy to break here
							
						
							////// next to erase chip 1, and ers_HV is a marco define, can be changed
							ChipErase(TEST_ESF_IDX ,ERS_HV_VALUE);
							
							u8buf[16] =u8buf[0] = 0x11;    // dummy to break here
							u8buf[15] =u8buf[0] = 0x11;    // dummy to break here
							u8buf[14] =u8buf[0] = 0x11;    // dummy to break here
							
							// ESF chip 1 read 8bit again to verify chip erase
							EsfRead(TEST_ESF_IDX, 0, 0, 1, &u8buf[0]);
							
							u8buf[16] =u8buf[0];    // dummy to break here
							u8buf[15] =u8buf[0];    // dummy to break here
							u8buf[14] =u8buf[0];    // dummy to break here
							
							// next, to program ESF with 0
							//u8buf[1] =u8buf[0] = 0;  
							u32buf[0]=0;      // note, dig prog always 32bit alignment
							Dig_Prog(TEST_ESF_IDX, PRGDIG_HV_VALUE , ENIP_PRGDIG_VALUE, ENBIAS_PRGDIG_VALUE, &u32buf[0], 1,0, 0);					
						
							u8buf[16] =u8buf[0] = 0x11;    // dummy to break here
							u8buf[15] =u8buf[0] = 0x11;    // dummy to break here
							u8buf[14] =u8buf[0] = 0x11;    // dummy to break here
							
							// ESF read again, to verify dig prog
							EsfRead(TEST_ESF_IDX, 0, 0, 1, &u8buf[0]);
							
							u8buf[16] =u8buf[0];    // dummy to break here
							u8buf[15] =u8buf[0];    // dummy to break here
							u8buf[14] =u8buf[0];    // dummy to break here
							
							/// offline test process done
					#endif
			#endif
		}
#endif

	}
}

void main_suspend_action(void)
{
	ui_powerdown();
}

void main_resume_action(void)
{
	ui_wakeup();
}

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

void main_remotewakeup_enable(void)
{
	ui_wakeup_enable();
}

void main_remotewakeup_disable(void)
{
	ui_wakeup_disable();
}

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)
{
	if (report[0] == 0xAA && report[1] == 0x55
			&& report[2] == 0xAA && report[3] == 0x55) {
		// Disconnect USB Device
		udc_stop();
		ui_powerdown();
	}
}

/**
 * \mainpage ASF USB Device HID Generic
 *
 * \section intro Introduction
 * This example shows how to implement a USB Device HID Generic
 * on Atmel MCU with USB module.
 * The application note AVR4905 http://ww1.microchip.com/downloads/en/AppNotes/doc8499.pdf
 * provides information about this implementation.
 *
 * \section startup Startup
 * The example uses the buttons or sensors available on the board
 * to simulate a standard generic.
 * After loading firmware, connect the board (EVKxx,Xplain,...) to the USB Host.
 * When connected to a USB host system this application provides a HID generic
 * application in the Unix/Mac/Windows operating systems.
 * This example uses the native HID driver for these operating systems.
 *
 * A Atmel PC tool allows to communicate with the HID generic device.
 * This document gives information on integrating the Atmel USB HID DLL functions.
 * Simple code examples that demonstrate different types of implementation are given.
 * http://ww1.microchip.com/downloads/en/AppNotes/doc7645.pdf
 * The PC tool is available here:
 * http://ww1.microchip.com/downloads/en/AppNotes/AVR153.zip
 * Note: Use the PID 0x2402 in tool graphical interface,
 * and the button Firmware Upgrade only disconnects the USB device.
 *
 * \copydoc UI
 *
 * \section example About example
 *
 * The example uses the following module groups:
 * - Basic modules:
 *   Startup, board, clock, interrupt, power management
 * - USB Device stack and HID modules:
 *   <br>services/usb/
 *   <br>services/usb/udc/
 *   <br>services/usb/class/hid/
 *   <br>services/usb/class/hid/generic/
 * - Specific implementation:
 *    - main.c,
 *      <br>initializes clock
 *      <br>initializes interrupt
 *      <br>manages UI
 *    - specific implementation for each target "./examples/product_board/":
 *       - conf_foo.h   configuration of each module
 *       - ui.c         implement of user's interface (buttons, leds)
 */
