#include "PAD.h"

/** Main program entry point. This routine contains the overall program flow, including initial
 *  setup of all components and the main program loop.
 */
int main(void){
	SetupHardware();

	LEDs_SetAllLEDs(LEDS_LED1 | LEDS_LED2);
	GlobalInterruptEnable();

	for (;;){
		USB_USBTask();
		PAD_Task();
	}
}

uint8_t led = 0;
void PAD_Task(void){
	if (USB_DeviceState != DEVICE_STATE_Configured)
		return;
	LEDs_SetAllLEDs(0);

	// receive from 328p & send to PC
	/* Notre convention :
	 *
	 *  328p -> 12u2 : 0bXYZZZZZZ
	 * X = 0 -> les Z sont les états de chaque boutons
	 * X = 1 & Y = 0 -> les Z correspondent à la valeur X du joystick
	 * X = 1 & Y = 1 -> les Z correspondent à la valeur Y du joystick
	 * 
	 * Cas 0b00ZZZZZZ : (boutons)
	 *  12u2 -> PC (endpoint button 1) : 0b000ZZZZZ
	 * Z : état d'un bouton
	
	 * Cas 0b1YZZZZZZ : (joystick)
	 *  12u2 -> PC (endpoint button 2) : 0bX0YYYYYY
	 * X = 0 -> valeur en X du joystick
	 * X = 1 -> valeur en Y du joystick
	 */
	if(Serial_IsCharReceived()){
		uint8_t byte = Serial_ReceiveByte();
		if((byte & 0x80) == 0){ // bouttons
			Endpoint_SelectEndpoint(PAD_IN_EP_BUTTON1);
			if (Endpoint_IsINReady() && Endpoint_IsReadWriteAllowed()){
				LEDs_SetAllLEDs(LEDS_LED1); //LED Tx
				Endpoint_Write_8(byte);
				Endpoint_ClearIN();
			}
		}else if((byte & 0x40) == 0){ // joystick X
			uint8_t toSend = (byte) & 0x3F;
			Endpoint_SelectEndpoint(PAD_IN_EP_BUTTON2);
			if (Endpoint_IsINReady() && Endpoint_IsReadWriteAllowed()){
				LEDs_SetAllLEDs(LEDS_LED1); //LED Tx
				Endpoint_Write_8(toSend);
				Endpoint_ClearIN();
			}
		}else{ // joystick Y
			uint8_t toSend = ((byte) & 0x3F) | 0x80;
			Endpoint_SelectEndpoint(PAD_IN_EP_BUTTON2);
			if (Endpoint_IsINReady() && Endpoint_IsReadWriteAllowed()){
				LEDs_SetAllLEDs(LEDS_LED1); //LED Tx
				Endpoint_Write_8(toSend);
				Endpoint_ClearIN();
			}
		}
	}

	// receive from PC & send to 328p
	/* Notre convention :
	 *
	 *  PC (endpoint led 1) -> 16u2 : 0b000XXXXX
	 * X = état d'une LED (LEDs 8 9 10 11 12)
	 *
	 *  PC (endpoint led 2) -> 16u2 : 0b0000000X
	 * X = état d'une LED (LED 13)
	 * 
	 *  16u2 -> 328p : 0bXYYYYYYY
	 * X = 0 -> pour les LEDs 8 9 10 11 12 13 (Y : les données)
	 */
	Endpoint_SelectEndpoint(PAD_OUT_EP_LED1);
	if (Endpoint_IsOUTReceived() && Endpoint_IsReadWriteAllowed()){
		LEDs_SetAllLEDs(LEDS_LED2); //LED Rx
		uint8_t byte = Endpoint_Read_8();
		led = (led & 0x20) | byte;
		Serial_SendByte(led);
		Endpoint_ClearOUT();
	}
	Endpoint_SelectEndpoint(PAD_OUT_EP_LED2);
	if (Endpoint_IsOUTReceived() && Endpoint_IsReadWriteAllowed()){
		LEDs_SetAllLEDs(LEDS_LED2); //LED Rx
		uint8_t byte = Endpoint_Read_8();
		led = (led & 0x1F) | byte << 5;
		Serial_SendByte(led);
		Endpoint_ClearOUT();
	}

	//LED Reset
	LEDs_SetAllLEDs(0);
}

/** Configures the board hardware and chip peripherals for the project's functionality. */
void SetupHardware(void){
#if (ARCH == ARCH_AVR8)
	/* Disable watchdog if enabled by bootloader/fuses */
	MCUSR &= ~(1 << WDRF);
	wdt_disable();

	/* Disable clock division */
	clock_prescale_set(clock_div_1);
#endif

	/* Hardware Initialization */
	USB_Init();
	LEDs_Init();
	Serial_Init(9600, 0);
}

// endpoints creation
void EVENT_USB_Device_ConfigurationChanged(void){
	/* Setup HID Report Endpoints */
	Endpoint_ConfigureEndpoint(PAD_OUT_EP_LED1  , EP_TYPE_INTERRUPT, PAD_EPSIZE, 1);
	Endpoint_ConfigureEndpoint(PAD_OUT_EP_LED2  , EP_TYPE_INTERRUPT, PAD_EPSIZE, 1);
	Endpoint_ConfigureEndpoint(PAD_IN_EP_BUTTON1, EP_TYPE_INTERRUPT, PAD_EPSIZE, 1);
	Endpoint_ConfigureEndpoint(PAD_IN_EP_BUTTON2, EP_TYPE_INTERRUPT, PAD_EPSIZE, 1);
}
