//**********************************************************************************************************************
//----------------------------------------------------------------------------------------------------------------------
//                                                    TIMERS
//----------------------------------------------------------------------------------------------------------------------
//*********************************************************************************************************************

#define TIMER_init(lbl0,lbl1) TMR timer ## lbl0 (lbl1)
#define ON_TIMER(lbl0,lbl1)  timer ##lbl0.sub(lbl1)
#define TIMER_STATE_VAR(lbl0) stateVAR[lbl0] 
#define TIMER_UPDATE(lbl0) timer ## lbl0.check()
#define TIMER_INTERVAL(lbl0,lbl1) timer ## lbl0.intervalo=lbl1
#define TIMER_ON(lbl0) timer ## lbl0.ON()
#define TIMER_OFF(lbl0) timer ## lbl0.OFF()


uint8_t stateVAR[10];						//Variables de las máquinas de estado de los timers (10 por default)
//#define SET_L PORTB=0x01;

class TMR
{
	private:
			uint32_t last_millis;
			uint32_t _millis;							//variable que almacena los ticks del sistema en milisegundos
			uint8_t TimerOnFlag=1;
			void (*iptr1)();
	public:
			uint16_t intervalo;
			uint8_t state;


	TMR (uint16_t _intervalo)
	{

		last_millis = millis();
		intervalo=_intervalo;

	}
	void sub(void (*kk)())
	{
		iptr1=kk;
	}
	void check(void)
	{

		if(TimerOnFlag)
		{
			_delay_us(1);
			if (millis() > last_millis + intervalo)
			{

				last_millis = millis();
				iptr1();
			}
		}
	}
	void Off(void)
	{
		TimerOnFlag=0;	
	}
	void On(void)
	{
		TimerOnFlag=1;
	}
};

//**********************************************************************************************************************
//----------------------------------------------------------------------------------------------------------------------
//                                                     PINES
//----------------------------------------------------------------------------------------------------------------------
//*********************************************************************************************************************
#define A1 (GPIOC,Pin1,OUTPUT)
#define A2 (GPIOC,Pin2,OUTPUT)
#define A3 (GPIOC,Pin3,OUTPUT)
#define A4 (GPIOC,Pin4,OUTPUT)
#define A5 (GPIOC,Pin5,OUTPUT)

#define BUTTON_Init(puerto, pin, pin_name) PIN pin_name (puerto, pin, INPUT) 
#define ON_BUTTON(pin_name, function_name) pin_name.DEBOUNCE_SUB(function_name)

#define GPIOA 0
#define GPIOB 1
#define GPIOC 2
#define GPIOD 3
#define GPIOE 4
#define GPIOF 5
#define GPIOG 6
#define GPIOH 7
#define GPIOJ 8
#define GPIOK 9
#define GPIOL 10
#define Pin0 0
#define Pin1 1
#define Pin2 2
#define Pin3 3
#define Pin4 4
#define Pin5 5
#define Pin6 6
#define Pin7 7

#define OUTPUT 1
#define INPUT 0

#define PIN_Init_D0(LBL1) PIN D0(GPIOD,Pin0,LBL1)
#define PIN_Init_D1(LBL1) PIN D1(GPIOD,Pin1,LBL1)
#define PIN_Init_D2(LBL1) PIN D2(GPIOD,Pin2,LBL1)
#define PIN_Init_D3(LBL1) PIN D3(GPIOD,Pin3,LBL1)
#define PIN_Init_D4(LBL1) PIN D4(GPIOD,Pin4,LBL1)
#define PIN_Init_D5(LBL1) PIN D5(GPIOD,Pin5,LBL1)
#define PIN_Init_D6(LBL1) PIN D6(GPIOD,Pin6,LBL1)
#define PIN_Init_D7(LBL1) PIN D7(GPIOD,Pin7,LBL1)
#define PIN_Init_D8(LBL1) PIN D8(GPIOB,Pin0,LBL1)
#define PIN_Init_D9(LBL1) PIN D9(GPIOB,Pin1,LBL1)
#define PIN_Init_D10(LBL1) PIN D10(GPIOB,Pin_2,LBL1)
#define PIN_Init_D11(LBL1) PIN D11(GPIOB,Pin_3,LBL1)
#define PIN_Init_D12(LBL1) PIN D12(GPIOB,Pin_4,LBL1)
#define PIN_Init_D13(LBL1) PIN D13(GPIOB,Pin_5,LBL1)
#define PIN_Init_A0(LBL1) PIN A0(GPIOC,Pin0,LBL1)
#define PIN_Init_A1(LBL1) PIN A1(GPIOC,Pin1,LBL1)
#define PIN_Init_A2(LBL1) PIN A2(GPIOC,Pin2,LBL1)
#define PIN_Init_A3(LBL1) PIN A3(GPIOC,Pin3,LBL1)
#define PIN_Init_A4(LBL1) PIN A4(GPIOC,Pin4,LBL1)
#define PIN_Init_A5(LBL1) PIN A5(GPIOC,Pin5,LBL1)
#define PIN_Init(puerto, pin, pin_name, modo) PIN pin_name(puerto, pin, modo)
#define SET(pin_name) pin_name.HI()
#define CLR(pin_name) pin_name.LO()
#define SET_State(pin_name, estado) pin_name.SET_STATE(estado)
#define GET_State(pin_name) pin_name.GET_STATE();
#define PIN_Toggle(pin_name) pin_name.TOGGLE()

//#define ON_BUTTON(puerto, pin, pin_name, function_name) PIN pin_name (puerto, pin, INPUT); pin_name.DEBOUNCE_SUB(function_name)
#define BUTTON(pin_name) pin_name.DEBOUNCE()


class PIN
{
	private:
		uint8_t *p_port;
		uint8_t *p_ddr;
		uint8_t *p_pin;
		uint8_t mask;
		uint8_t state;
		uint32_t initial_millis;
		void (*iptr1)();
	public:
		PIN (uint8_t _puerto, uint8_t _pin, uint8_t _modo)
		{
			mask = _pin;
			if (_puerto<7)
			{
				p_pin = (uint8_t *)(3 * _puerto) + 0X20;
				p_ddr = (uint8_t *)(3 * _puerto) + 0X21;
				p_port = (uint8_t *)(3 * _puerto) + 0X22;
			}
			else
			{
				_puerto -=7;
				p_pin = (uint8_t *)(3 * _puerto) + 0X100;
				p_ddr = (uint8_t *)(3 * _puerto) + 0X101;
				p_port = (uint8_t *)(3 * _puerto) + 0X102;
			}
			if (_modo)
			*p_ddr |= (1 << mask);
			else
			{
				*p_port |= (1 << mask);
				*p_ddr &= ~(1 << mask);
			}
		}
	
	void MODE  (uint8_t _modo)
	{
		if (_modo)
			*p_ddr |= (1 << mask);
		else
		{
			*p_ddr &= ~(1 << mask);
		}		
	}
	void HI(void)
	{
		*p_port |= (1<<mask);
	}
	void LO(void)
	{
		*p_port &= ~(1<<mask);
	}
	void SET_STATE(uint8_t _state)
	{
		if (_state)
			*p_port |= (1<<mask);
		else
			*p_port &= ~(1<<mask);
	}
	uint8_t GET_STATE(void)
	{
		if (*p_pin & (1<<mask))
		return 1;
		else
		return 0;
	}
	void TOGGLE(void)
	{
		*p_port ^= (1<<mask);
	}
	void DEBOUNCE_SUB(void (*kk)())
	{
		iptr1=kk;
	}

	void DEBOUNCE(void)
	{
		switch(state)
		{
			case 0:
			if (!(*p_pin & (1<<mask)))
			{
				state=1;
				initial_millis = millis();
			}
			break;
			case 1:
			if (millis()>(initial_millis + 200))
			{
				state=2;
			}
			break;
			case 2:
			if (*p_pin & (1<<mask))
			{
				state=0;
				iptr1();
			}
			break;
		}
	}	
};

/************************************************************************************************************************
                                                 VARIABLES
***************************************************************************************************************************/
PIN_Init_D2(OUTPUT);
PIN_Init_D3(OUTPUT);
BUTTON_Init(GPIOD,Pin4, button1);
TMR timer1(500);
TMR timer2(750);

/************************************************************************************************************************
                                                 FUNCIONES
***************************************************************************************************************************/
void buttonFunction1()
{
  timer1.Off();
}
void functionT1()
{
  D2.TOGGLE();
}
void functionT2()
{
  D3.TOGGLE();
}

/************************************************************************************************************************
                                                 Programa
***************************************************************************************************************************/
void setup() {
  // put your setup code here, to run once:
	Serial.begin(9600);
	Serial.println("Hola amiguitos");
	timer1.sub(functionT1);
	timer2.sub(functionT2);
}
void loop() {
	timer1.check();
	timer2.check();
}