        // TODO 4.01
        USB_DEVICE_HANDLE usbDevHandle;

            // TODO 4.02
            appData.usbDevHandle = USB_DEVICE_Open(USB_DEVICE_INDEX_0, 0);
            appInitialized &= (appData.usbDevHandle != USB_DEVICE_HANDLE_INVALID);


                // TODO 4.03
                USB_DEVICE_EventHandlerSet(appData.usbDevHandle, APP_USBDeviceEventHandler, 0);

// TODO 4.04
USB_DEVICE_EVENT_RESPONSE APP_USBDeviceEventHandler(USB_DEVICE_EVENT event, void * eventData, uintptr_t context)
{
}

// TODO 4.05
USB_DEVICE_EVENT_RESPONSE APP_USBDeviceEventHandler(USB_DEVICE_EVENT event, void * pData, uintptr_t context)
{
    uint8_t activeConfiguration;

    // Handling of each event
    switch (event)
    {
    case USB_DEVICE_EVENT_POWER_DETECTED:

        // This means the device detected a valid VBUS voltage
        // and is attached to the USB if the device is bus powered.
        break;

    case USB_DEVICE_EVENT_POWER_REMOVED:

        // This means the device is not attached to the USB.
        break;

    case USB_DEVICE_EVENT_SUSPENDED:

        // The bus is idle. There was no activity detected.
        // The application can switch to a low power mode after
        // exiting the event handler.
        break;

    case USB_DEVICE_EVENT_SOF:

        // A start of frame was received. This is a periodic
        // event and can be used the application for time
        // related activities. pData will point to a USB_DEVICE_EVENT_DATA_SOF type data
        // containing the frame number.

        // Example code for retriveing the frame number.
        // frameNumber = ((USB_DEVICE_EVENT_DATA_SOF *)(pData))->frameNumber;

        break;

    case USB_DEVICE_EVENT_RESET:

        // Reset signalling was detected on the bus. The
        // application can find out the attach speed.

        // Example code for retriveing the speed
        // attachSpeed = USB_DEVICE_ActiveSpeedGet(usbDeviceHandle);

        break;

    case USB_DEVICE_EVENT_DECONFIGURED:

        // This indicates that host has deconfigured the device i.e., it
        // has set the configuration as 0. All function driver instances
        // would have been deinitialized.

        break;

    case USB_DEVICE_EVENT_ERROR:

        // This means an unknown error has occurred on the bus.
        // The application can try detaching and attaching the
        // device again.
        break;

    case USB_DEVICE_EVENT_CONFIGURED:

        // This means that device is configured and the application can
        // start using the device functionality. The application must
        // register function driver event handlers within this event.
        // The pData parameter will be a pointer to a USB_DEVICE_EVENT_DATA_CONFIGURED data type
        // that contains the active configuration number.

        activeConfiguration = ((USB_DEVICE_EVENT_DATA_CONFIGURED *) (pData))->configurationValue;
        if (activeConfiguration == 1)
        {
            // Device is enumerated. Register here the USB Function Driver Event Handler function.
        }
        break;

    case USB_DEVICE_EVENT_RESUMED:

        // This means that the resume signalling was detected on the
        // bus. The application can bring the device out of power
        // saving mode.

        break;

    case USB_DEVICE_EVENT_CONTROL_TRANSFER_SETUP_REQUEST:

        // This means that the setup stage of the control transfer is in
        // progress and a setup packet has been received. The pData
        // parameter will point to a USB_SETUP_PACKET data type The
        // application can process the command and update its control
        // transfer state machine. The application for example could call
        // the USB_DEVICE_ControlReceive() function (as shown here) to
        // submit the buffer that would receive data in case of a
        // control read transfer.
        // Example:
        // setupEventData = (USB_SETUP_PACKET *)pData;

        // Application can now respond to the Setup packet by submitting a buffer
        // to receive 32 bytes in the  control write transfer
        // USB_DEVICE_ControlReceive(appData.usbDevHandle, data, 32);
        break;

    case USB_DEVICE_EVENT_CONTROL_TRANSFER_DATA_RECEIVED:

        // This means that data in the data stage of the control write
        // transfer has been received. The application can either accept
        // the received data by calling the USB_DEVICE_ControlStatus()
        // function with USB_DEVICE_CONTROL_STATUS_OK flag (as shown in
        // this example) or it can reject it by calling the
        // USB_DEVICE_ControlStatus() function with
        // USB_DEVICE_CONTROL_STATUS_ERROR flag.

        USB_DEVICE_ControlStatus(usbDeviceHandle, USB_DEVICE_CONTROL_STATUS_OK);
        break;

    case USB_DEVICE_EVENT_CONTROL_TRANSFER_DATA_SENT:

        // This means that data in the data stage of the control
        // read transfer has been sent.
        break;

    case USB_DEVICE_EVENT_CONTROL_TRANSFER_ABORTED:

        // This means the host has aborted the control transfer. The
        // application can reset it's control transfer state machine.

        break;

    default:
        break;
    }

    return USB_DEVICE_EVENT_RESPONSE_NONE;
}

        // TODO 4.06
        //USB_DEVICE_ControlStatus(usbDeviceHandle, USB_DEVICE_CONTROL_STATUS_OK);
        USB_DEVICE_ControlStatus(appData.usbDevHandle, USB_DEVICE_CONTROL_STATUS_OK);

        // TODO 4.07
        USB_DEVICE_Attach(appData.usbDevHandle);

            // TODO 4.08
            appData.deviceIsConfigured = true;

        // TODO 4.09
        bool deviceIsConfigured;

        // TODO 4.10
        USB_DEVICE_Detach(appData.usbDevHandle);
        appData.deviceIsConfigured = false;
