/** Task to set the configuration of the attached device after it has been enumerated, and to read in
 *  data received from the attached RNDIS device and print it to the serial port.
 */
void RNDIS_Host_Task(void)
{
    uint8_t ErrorCode;

    switch (USB_HostState)
    {
    case HOST_STATE_Addressed:
        puts_P(PSTR("Getting Config Data.\r\n"));

        /* Get and process the configuration descriptor data */
        if ((ErrorCode = ProcessConfigurationDescriptor()) != SuccessfulConfigRead)
        {
            if (ErrorCode == ControlError)
                puts_P(PSTR(ESC_FG_RED "Control Error (Get Configuration).\r\n"));
            else
                puts_P(PSTR(ESC_FG_RED "Invalid Device.\r\n"));

            printf_P(PSTR(" -- Error Code: %d\r\n" ESC_FG_WHITE), ErrorCode);

            /* Indicate error via status LEDs */
            LEDs_SetAllLEDs(LEDMASK_USB_ERROR);

            /* Wait until USB device disconnected */
            USB_HostState = HOST_STATE_WaitForDeviceRemoval;
            break;
        }

        /* Set the device configuration to the first configuration (rarely do devices use multiple configurations) */
        if ((ErrorCode = USB_Host_SetDeviceConfiguration(1)) != HOST_SENDCONTROL_Successful)
        {
            printf_P(PSTR(ESC_FG_RED "Control Error (Set Configuration).\r\n"
                          " -- Error Code: %d\r\n" ESC_FG_WHITE), ErrorCode);

            /* Indicate error via status LEDs */
            LEDs_SetAllLEDs(LEDMASK_USB_ERROR);

            /* Wait until USB device disconnected */
            USB_HostState = HOST_STATE_WaitForDeviceRemoval;
            break;
        }

        uint16_t DeviceMaxPacketSize;
        if ((ErrorCode = RNDIS_InitializeDevice(1024, &DeviceMaxPacketSize)) != HOST_SENDCONTROL_Successful)
        {
            printf_P(PSTR(ESC_FG_RED "Error Initializing Device.\r\n"
                          " -- Error Code: %d\r\n" ESC_FG_WHITE), ErrorCode);

            /* Indicate error via status LEDs */
            LEDs_SetAllLEDs(LEDMASK_USB_ERROR);

            /* Wait until USB device disconnected */
            USB_HostState = HOST_STATE_WaitForDeviceRemoval;
            break;
        }

        printf_P(PSTR("Device Max Transfer Size: %lu bytes.\r\n"), DeviceMaxPacketSize);

        /* We set the default filter to only receive packets we would be interested in */
        uint32_t PacketFilter = (REMOTE_NDIS_PACKET_DIRECTED | REMOTE_NDIS_PACKET_BROADCAST | REMOTE_NDIS_PACKET_ALL_MULTICAST);
        if ((ErrorCode = RNDIS_SetRNDISProperty(OID_GEN_CURRENT_PACKET_FILTER,
                                                &PacketFilter, sizeof(PacketFilter))) != HOST_SENDCONTROL_Successful)
        {
            printf_P(PSTR(ESC_FG_RED "Error Setting Device Packet Filter.\r\n"
                          " -- Error Code: %d\r\n" ESC_FG_WHITE), ErrorCode);

            /* Indicate error via status LEDs */
            LEDs_SetAllLEDs(LEDMASK_USB_ERROR);

            /* Wait until USB device disconnected */
            USB_HostState = HOST_STATE_WaitForDeviceRemoval;
            break;
        }

        uint32_t VendorID;
        if ((ErrorCode = RNDIS_QueryRNDISProperty(OID_GEN_VENDOR_ID,
                         &VendorID, sizeof(VendorID))) != HOST_SENDCONTROL_Successful)
        {
            printf_P(PSTR(ESC_FG_RED "Error Getting Vendor ID.\r\n"
                          " -- Error Code: %d\r\n" ESC_FG_WHITE), ErrorCode);

            /* Indicate error via status LEDs */
            LEDs_SetAllLEDs(LEDMASK_USB_ERROR);

            /* Wait until USB device disconnected */
            USB_HostState = HOST_STATE_WaitForDeviceRemoval;
            break;
        }

        printf_P(PSTR("Device Vendor ID: 0x%08lX\r\n"), VendorID);

        puts_P(PSTR("RNDIS Device Enumerated.\r\n"));

        USB_HostState = HOST_STATE_Configured;
        break;
    case HOST_STATE_Configured:
        PrintIncomingPackets();

        break;
    }
}
/** Main program entry point. This routine configures the hardware required by the application, then
 *  enters a loop to run the application tasks in sequence.
 */
int main(void)
{
	SetupHardware();

	puts_P(PSTR(ESC_FG_CYAN "RNDIS Host Demo running.\r\n" ESC_FG_WHITE));

	LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
	sei();

	for (;;)
	{
		switch (USB_HostState)
		{
			case HOST_STATE_Addressed:
				LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING);

				uint16_t ConfigDescriptorSize;
				uint8_t  ConfigDescriptorData[512];

				if (USB_Host_GetDeviceConfigDescriptor(1, &ConfigDescriptorSize, ConfigDescriptorData,
				                                       sizeof(ConfigDescriptorData)) != HOST_GETCONFIG_Successful)
				{
					puts_P(PSTR("Error Retrieving Configuration Descriptor.\r\n"));
					LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
					USB_HostState = HOST_STATE_WaitForDeviceRemoval;
					break;
				}

				if (RNDIS_Host_ConfigurePipes(&Ethernet_RNDIS_Interface,
				                              ConfigDescriptorSize, ConfigDescriptorData) != RNDIS_ENUMERROR_NoError)
				{
					puts_P(PSTR("Attached Device Not a Valid RNDIS Class Device.\r\n"));
					LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
					USB_HostState = HOST_STATE_WaitForDeviceRemoval;
					break;
				}

				if (USB_Host_SetDeviceConfiguration(1) != HOST_SENDCONTROL_Successful)
				{
					puts_P(PSTR("Error Setting Device Configuration.\r\n"));
					LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
					USB_HostState = HOST_STATE_WaitForDeviceRemoval;
					break;
				}

				if (RNDIS_Host_InitializeDevice(&Ethernet_RNDIS_Interface) != HOST_SENDCONTROL_Successful)
				{
					puts_P(PSTR("Error Initializing Device.\r\n"));

					LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
					USB_HostState = HOST_STATE_WaitForDeviceRemoval;
					break;
				}

				printf_P(PSTR("Device Max Transfer Size: %lu bytes.\r\n"), Ethernet_RNDIS_Interface.State.DeviceMaxPacketSize);

				uint32_t PacketFilter = (REMOTE_NDIS_PACKET_DIRECTED | REMOTE_NDIS_PACKET_BROADCAST | REMOTE_NDIS_PACKET_ALL_MULTICAST);
				if (RNDIS_Host_SetRNDISProperty(&Ethernet_RNDIS_Interface, OID_GEN_CURRENT_PACKET_FILTER,
				                                &PacketFilter, sizeof(PacketFilter)) != HOST_SENDCONTROL_Successful)
				{
					puts_P(PSTR("Error Setting Device Packet Filter.\r\n"));

					LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
					USB_HostState = HOST_STATE_WaitForDeviceRemoval;
					break;
				}

				uint32_t VendorID;
				if (RNDIS_Host_QueryRNDISProperty(&Ethernet_RNDIS_Interface, OID_GEN_VENDOR_ID,
				                                  &VendorID, sizeof(VendorID)) != HOST_SENDCONTROL_Successful)
				{
					puts_P(PSTR("Error Getting Vendor ID.\r\n"));

					LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
					USB_HostState = HOST_STATE_WaitForDeviceRemoval;
					break;
				}

				printf_P(PSTR("Device Vendor ID: 0x%08lX\r\n"), VendorID);

				puts_P(PSTR("RNDIS Device Enumerated.\r\n"));
				LEDs_SetAllLEDs(LEDMASK_USB_READY);
				USB_HostState = HOST_STATE_Configured;
				break;
			case HOST_STATE_Configured:
				PrintIncomingPackets();

				break;
		}

		RNDIS_Host_USBTask(&Ethernet_RNDIS_Interface);
		USB_USBTask();
	}
}