// TODO 5.01
// TODO 5.02
uint16_t breakDuration;
USB_DEVICE_HANDLE usbDeviceHandle;
USB_CDC_LINE_CODING lineCoding;
USB_CDC_CONTROL_LINE_STATE * controlLineStateData;

USB_DEVICE_CDC_EVENT_RESPONSE USBDeviceCDCEventHandler
(
 USB_DEVICE_CDC_INDEX instanceIndex,
 USB_DEVICE_CDC_EVENT event,
 void * pData,
 uintptr_t userData
 )
{
    switch (event)
    {
    case USB_DEVICE_CDC_EVENT_SET_LINE_CODING:

        // In this case, the application should read the line coding
        // data that is sent by the host.
        // TODO 5.04

        break;

    case USB_DEVICE_CDC_EVENT_GET_LINE_CODING:

        // In this case, the application should send the line coding
        // data to the host.

        // TODO 5.05

        break;

    case USB_DEVICE_CDC_EVENT_SET_CONTROL_LINE_STATE:

        // In this case, pData should be interpreted as a
        // USB_CDC_CONTROL_LINE_STATE pointer type.  The application
        // acknowledges the parameters by calling the
        // USB_DEVICE_ControlStatus() function with the
        // USB_DEVICE_CONTROL_STATUS_OK option.

        // TODO 5.06

        break;

    case USB_DEVICE_CDC_EVENT_SEND_BREAK:

        // In this case, pData should be interpreted as a
        // USB_DEVICE_CDC_EVENT_DATA_SEND_BREAK pointer type
        // to the break duration. The application acknowledges
        // the parameters by calling the USB_DEVICE_ControlStatus()
        // function with the USB_DEVICE_CONTROL_STATUS_OK option.

        // TODO 5.07

        break;

    case USB_DEVICE_CDC_EVENT_CONTROL_TRANSFER_DATA_SENT:

        // This event indicates the data send request associated with
        // the latest USB_DEVICE_ControlSend() function was
        // completed.  The application could use this event to track
        // the completion of the USB_DEVICE_CDC_EVENT_GET_LINE_CODING
        // request.

        break;

    case USB_DEVICE_CDC_EVENT_CONTROL_TRANSFER_DATA_RECEIVED:

        // This means that the data stage is complete. The data in
        // setLineCodingData is valid or data in getLineCodingData was
        // sent to the host.  The application can now decide whether it
        // supports this data. It is not mandatory to do this in the
        // event handler.

        // TODO 5.08

        break;

    case USB_DEVICE_CDC_EVENT_WRITE_COMPLETE:

        // This means USB_DEVICE_CDC_Write() operation completed.
        // The pData member will point to a
        // USB_DEVICE_CDC_EVENT_DATA_WRITE_COMPLETE type of data.
  
        //TODO 5.21
  
        break;

    case USB_DEVICE_CDC_EVENT_READ_COMPLETE:

        // This means USB_DEVICE_CDC_Read() operation completed.
        // The pData member will point to a
        // USB_DEVICE_CDC_EVENT_DATA_READ_COMPLETE type of data.
        
        //TODO 5.16

        break;

    case USB_DEVICE_CDC_EVENT_SERIAL_STATE_NOTIFICATION_COMPLETE:

        // This means USB_DEVICE_CDC_SerialStateNotification() operation
        // completed. The pData member will point to a
        // USB_DEVICE_CDC_EVENT_DATA_SERIAL_STATE_NOTIFICATION_COMPLETE type of data.

        break;

    default:
        break;
    }

    return USB_DEVICE_CDC_EVENT_RESPONSE_NONE;
}

// TODO 5.02
//uint16_t breakDuration;
//USB_DEVICE_HANDLE usbDeviceHandle;
//USB_CDC_LINE_CODING lineCoding;
//USB_CDC_CONTROL_LINE_STATE * controlLineStateData;

        // TODO 5.03
        uint16_t breakDuration;
        USB_CDC_LINE_CODING lineCoding;
        USB_CDC_CONTROL_LINE_STATE * controlLineStateData;

        // TODO 5.04
        //USB_DEVICE_ControlReceive(usbDeviceHandle, &lineCoding,
        //                         sizeof (USB_CDC_LINE_CODING));
        USB_DEVICE_ControlReceive(appData.usbDevHandle, &appData.lineCoding,
                                  sizeof (USB_CDC_LINE_CODING));

        // TODO 5.05
        //USB_DEVICE_ControlSend(usbDeviceHandle, &lineCoding,
        //                       sizeof (USB_CDC_LINE_CODING));
        USB_DEVICE_ControlSend(appData.usbDevHandle, &appData.lineCoding,
                               sizeof (USB_CDC_LINE_CODING));

        // TODO 5.06
        //controlLineStateData = (USB_CDC_CONTROL_LINE_STATE *) pData;
        //USB_DEVICE_ControlStatus(usbDeviceHandle, USB_DEVICE_CONTROL_STATUS_OK);
        appData.controlLineStateData = (USB_CDC_CONTROL_LINE_STATE *) pData;
        USB_DEVICE_ControlStatus(appData.usbDevHandle, USB_DEVICE_CONTROL_STATUS_OK);

        // TODO 5.07
        //breakDuration = ((USB_DEVICE_CDC_EVENT_DATA_SEND_BREAK *) pData)->breakDuration;
        //USB_DEVICE_ControlStatus(usbDeviceHandle, USB_DEVICE_CONTROL_STATUS_OK);
        appData.breakDuration = ((USB_DEVICE_CDC_EVENT_DATA_SEND_BREAK *) pData)->breakDuration;
        USB_DEVICE_ControlStatus(appData.usbDevHandle, USB_DEVICE_CONTROL_STATUS_OK);

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

// TODO 5.09
#include "usb/usb_device_cdc.h"

// TODO 5.10
    #include "usb/usb_device_cdc.h"

            //TODO 5.11
            USB_DEVICE_CDC_EventHandlerSet(USB_DEVICE_CDC_INDEX_0, USBDeviceCDCEventHandler, 0);
            appData.deviceIsConfigured = true;

        // TODO 5.12
        //APP_STATE_INIT = 0,
        //APP_STATE_SERVICE_TASKS,
        APP_STATE_INIT = 0,
        APP_STATE_WAIT_CONFIGURED,
        APP_STATE_SERVICE_TASKS,

            //TODO 5.13
            //appData.state = APP_STATE_SERVICE_TASKS;
            appData.state = APP_STATE_WAIT_CONFIGURED;

    //TODO 5.14
    case APP_STATE_WAIT_CONFIGURED:
    {
    //TODO 5.17
    break;
    }

        //TODO 5.15
        volatile bool cdcReadCompleted;
        USB_DEVICE_CDC_TRANSFER_HANDLE readTransferHandle;
        uint8_t CDCrxDataBuffer[64] __attribute__((aligned(32)));

        //TODO 5.16
        appData.cdcReadCompleted = true;

        //TODO 5.17
        if (appData.deviceIsConfigured)
        {
            appData.cdcReadCompleted = false;
            USB_DEVICE_CDC_Read(USB_DEVICE_CDC_INDEX_0, &appData.readTransferHandle, appData.CDCrxDataBuffer, 64);
            appData.state = APP_STATE_SERVICE_TASKS;
        }

        //TODO 5.18
        if (appData.cdcReadCompleted)
        {
            switch (appData.CDCrxDataBuffer[0])
            {
            case '1':
                LED1_Toggle();
                break;
            case '2':
                LED2_Toggle();
                break;
            case '3':
                LED3_Toggle();
                break;
            }
            appData.cdcReadCompleted = false;
            USB_DEVICE_CDC_Read(USB_DEVICE_CDC_INDEX_0, &appData.readTransferHandle, appData.CDCrxDataBuffer, 256);
        }

//TODO 5.19
#include "peripheral/port/plib_port.h"

        //TODO 5.20
        volatile bool cdcWriteCompleted;
        USB_DEVICE_CDC_TRANSFER_HANDLE writeTransferHandle;
        uint8_t CDCtxDataBuffer[64] __attribute__((aligned(32)));

        //TODO 5.21
        appData.cdcWriteCompleted = true;

        //TODO 5.22
        if (appData.cdcWriteCompleted)
        {
            if (!BT1_Get())
            {
                static uint16_t i = 0;
                appData.cdcWriteCompleted = false;
                sprintf((char *) appData.CDCtxDataBuffer, "BT1 Pressed! (%05d)\r\n", ++i);
                USB_DEVICE_CDC_Write(USB_DEVICE_CDC_INDEX_0, &appData.writeTransferHandle, appData.CDCtxDataBuffer, sizeof (appData.CDCtxDataBuffer), USB_DEVICE_TRANSFER_FLAGS_DATA_COMPLETE);
            }
        }

//TODO 5.23
#include <stdio.h>

            //TODO 5.24
            appData.lineCoding.dwDTERate = 9600;
            appData.lineCoding.bParityType = 0;
            appData.lineCoding.bDataBits = 8;
            appData.lineCoding.bCharFormat = 0;
            appData.cdcReadCompleted = false;
            appData.cdcWriteCompleted = true;