/***************************************************************************//**
* \file CDC_midi.c
* \version 3.20
*
* \brief
*  MIDI Streaming request handler.
*  This file contains routines for sending and receiving MIDI
*  messages, and handles running status in both directions.
*
* Related Document:
*  Universal Serial Bus Device Class Definition for MIDI Devices Release 1.0
*  MIDI 1.0 Detailed Specification Document Version 4.2
*
********************************************************************************
* \copyright
* Copyright 2008-2016, Cypress Semiconductor Corporation.  All rights reserved.
* You may use this file only in accordance with the license, terms, conditions,
* disclaimers, and limitations in the end user license agreement accompanying
* the software package with which this file was provided.
*******************************************************************************/

#include "CDC_midi.h"
#include "CDC_pvt.h"
#include "cyapicallbacks.h"

#if defined(CDC_ENABLE_MIDI_STREAMING)

/***************************************
*    MIDI Constants
***************************************/

#if (CDC_MIDI_EXT_MODE >= CDC_ONE_EXT_INTRF)
    /* The Size of the MIDI messages (MIDI Table 4-1) */
    static const uint8 CYCODE CDC_MIDI_SIZE[] = {
    /*  Miscellaneous function codes(Reserved)  */ 0x03u,
    /*  Cable events (Reserved)                 */ 0x03u,
    /*  Two-byte System Common messages         */ 0x02u,
    /*  Three-byte System Common messages       */ 0x03u,
    /*  SysEx starts or continues               */ 0x03u,
    /*  Single-byte System Common Message or
        SysEx ends with following single byte   */ 0x01u,
    /*  SysEx ends with following two bytes     */ 0x02u,
    /*  SysEx ends with following three bytes   */ 0x03u,
    /*  Note-off                                */ 0x03u,
    /*  Note-on                                 */ 0x03u,
    /*  Poly-KeyPress                           */ 0x03u,
    /*  Control Change                          */ 0x03u,
    /*  Program Change                          */ 0x02u,
    /*  Channel Pressure                        */ 0x02u,
    /*  PitchBend Change                        */ 0x03u,
    /*  Single Byte                             */ 0x01u
    };
#endif  /* CDC_MIDI_EXT_MODE >= CDC_ONE_EXT_INTRF */



/***************************************
*  Global variables
***************************************/


#if (CDC_MIDI_IN_BUFF_SIZE > 0)
    #if (CDC_MIDI_IN_BUFF_SIZE >= 256)
        /** Input endpoint buffer pointer. This pointer is used as an index for the
        * USBMIDI_midiInBuffer to write data. It is cleared to zero by the
        * USBMIDI_MIDI_EP_Init() function.*/
        volatile uint16 CDC_midiInPointer;                            /* Input endpoint buffer pointer */
    #else
        volatile uint8 CDC_midiInPointer;                             /* Input endpoint buffer pointer */
    #endif /* (CDC_MIDI_IN_BUFF_SIZE >= 256) */
    /** Contains the midi IN endpoint number, It is initialized after a
     * SET_CONFIGURATION request based on a user descriptor. It is used in MIDI
     * APIs to send data to the host.*/
    volatile uint8 CDC_midi_in_ep;
    /** Input endpoint buffer with a length equal to MIDI IN EP Max Packet Size.
     * This buffer is used to save and combine the data received from the UARTs,
     * generated internally by USBMIDI_PutUsbMidiIn() function messages, or both.
     * The USBMIDI_MIDI_IN_Service() function transfers the data from this buffer to the host.*/
    uint8 CDC_midiInBuffer[CDC_MIDI_IN_BUFF_SIZE];       /* Input endpoint buffer */
#endif /* (CDC_MIDI_IN_BUFF_SIZE > 0) */

#if (CDC_MIDI_OUT_BUFF_SIZE > 0)
    /** Contains the midi OUT endpoint number. It is initialized after a
     * SET_CONFIGURATION request based on a user descriptor. It is used in
     * MIDI APIs to receive data from the host.*/
    volatile uint8 CDC_midi_out_ep;                                   /* Output endpoint number */
    /** Output endpoint buffer with a length equal to MIDI OUT EP Max Packet Size.
     * This buffer is used by the USBMIDI_MIDI_OUT_EP_Service() function to save
     * the data received from the host. The received data is then parsed. The
     * parsed data is transferred to the UARTs buffer and also used for internal
     * processing by the USBMIDI_callbackLocalMidiEvent() function.*/
    uint8 CDC_midiOutBuffer[CDC_MIDI_OUT_BUFF_SIZE];     /* Output endpoint buffer */
#endif /* (CDC_MIDI_OUT_BUFF_SIZE > 0) */

#if (CDC_MIDI_EXT_MODE >= CDC_ONE_EXT_INTRF)

    static CDC_MIDI_RX_STATUS CDC_MIDI1_Event;            /* MIDI RX status structure */
    static volatile uint8 CDC_MIDI1_TxRunStat;                         /* MIDI Output running status */
    /** The USBFS supports a maximum of two external Jacks. The two flag variables
     * are used to represent the status of two external Jacks. These optional variables
     * are allocated when External Mode is enabled. The following flags help to
     * detect and generate responses for SysEx messages. The USBMIDI_MIDI2_InqFlags
     * is optional and is not available when only one external Jack is configured.
     * Flag                          | Description
     * ------------------------------|---------------------------------------
     * USBMIDI_INQ_SYSEX_FLAG        | Non-real-time SysEx message received.
     * USBMIDI_INQ_IDENTITY_REQ_FLAG | Identity Request received. You should clear this bit when an Identity Reply message is generated.
     * SysEX messages are intended for local device and shouldn't go out on the
     * external MIDI jack, this flag indicates when a MIDI SysEx OUT message is
     * in progress for the application */
    volatile uint8 CDC_MIDI1_InqFlags;                                 /* Device inquiry flag */

    #if (CDC_MIDI_EXT_MODE >= CDC_TWO_EXT_INTRF)
        static CDC_MIDI_RX_STATUS CDC_MIDI2_Event;        /* MIDI RX status structure */
        static volatile uint8 CDC_MIDI2_TxRunStat;                     /* MIDI Output running status */
        /** See description of \ref CDC_MIDI1_InqFlags*/
        volatile uint8 CDC_MIDI2_InqFlags;                             /* Device inquiry flag */
    #endif /* (CDC_MIDI_EXT_MODE >= CDC_TWO_EXT_INTRF) */
#endif /* (CDC_MIDI_EXT_MODE >= CDC_ONE_EXT_INTRF) */


/***************************************
* Custom Declarations
***************************************/

/* `#START MIDI_CUSTOM_DECLARATIONS` Place your declaration here */

/* `#END` */


#if (CDC_ENABLE_MIDI_API != 0u)
/*******************************************************************************
* Function Name: CDC_MIDI_Init
****************************************************************************//**
*
*  This function initializes the MIDI interface and UART(s) to be ready to
*   receive data from the PC and MIDI ports.
*
* \globalvars
*
*  \ref CDC_midiInBuffer: This buffer is used for saving and combining
*    the received data from UART(s) and(or) generated internally by
*    PutUsbMidiIn() function messages. CDC_MIDI_IN_EP_Service()
*    function transfers the data from this buffer to the PC.
*
*  \ref CDC_midiOutBuffer: This buffer is used by the
*    CDC_MIDI_OUT_Service() function for saving the received
*    from the PC data, then the data are parsed and transferred to UART(s)
*    buffer and to the internal processing by the
*
*  \ref CDC_callbackLocalMidiEvent function.
*
*  \ref CDC_midi_out_ep: Used as an OUT endpoint number.
*
*  \ref CDC_midi_in_ep: Used as an IN endpoint number.
*
*   \ref CDC_midiInPointer: Initialized to zero.
*
* \sideeffect
*   The priority of the UART RX ISR should be higher than UART TX ISR. To do
*   that this function changes the priority of the UARTs TX and RX interrupts.
*
* \reentrant
*  No
*
*******************************************************************************/
void CDC_MIDI_Init(void) 
{
#if (CDC_MIDI_IN_BUFF_SIZE > 0)
   CDC_midiInPointer = 0u;
#endif /* (CDC_MIDI_IN_BUFF_SIZE > 0) */

#if (CDC_EP_MANAGEMENT_DMA_AUTO)
    #if (CDC_MIDI_IN_BUFF_SIZE > 0)
        /* Provide buffer for IN endpoint. */
        CDC_LoadInEP(CDC_midi_in_ep, CDC_midiInBuffer,
                                                               CDC_MIDI_IN_BUFF_SIZE);
    #endif  /* (CDC_MIDI_IN_BUFF_SIZE > 0) */

    #if (CDC_MIDI_OUT_BUFF_SIZE > 0)
        /* Provide buffer for OUT endpoint. */
        (void)CDC_ReadOutEP(CDC_midi_out_ep, CDC_midiOutBuffer,
                                                                       CDC_MIDI_OUT_BUFF_SIZE);
    #endif /* (CDC_MIDI_OUT_BUFF_SIZE > 0) */
#endif /* (CDC_EP_MANAGEMENT_DMA_AUTO) */

#if (CDC_MIDI_OUT_BUFF_SIZE > 0)
    CDC_EnableOutEP(CDC_midi_out_ep);
#endif /* (CDC_MIDI_OUT_BUFF_SIZE > 0) */

    /* Initialize the MIDI port(s) */
#if (CDC_MIDI_EXT_MODE >= CDC_ONE_EXT_INTRF)
    CDC_MIDI_InitInterface();
#endif /* (CDC_MIDI_EXT_MODE >= CDC_ONE_EXT_INTRF) */
}


#if (CDC_MIDI_OUT_BUFF_SIZE > 0)
    /*******************************************************************************
    * Function Name: CDC_MIDI_OUT_Service
    ****************************************************************************//**
    *
    *  This function services the traffic from the USBMIDI OUT endpoint and
    *  sends the data to the MIDI output ports (TX UARTs). It is blocked by the
    *  UART when not enough space is available in the UART TX buffer.
    *  This function is automatically called from OUT EP ISR in DMA with
    *  Automatic Memory Management mode. In Manual and DMA with Manual EP
    *  Management modes you must call it from the main foreground task.
    *
    * \globalvars
    *
    *  \ref CDC_midiOutBuffer: Used as temporary buffer between USB
    *       internal memory and UART TX buffer.
    *
    *  \ref CDC_midi_out_ep: Used as an OUT endpoint number.
    *
    * \reentrant
    *  No
    *
    *******************************************************************************/
    void CDC_MIDI_OUT_Service(void) 
    {
    #if (CDC_MIDI_OUT_BUFF_SIZE >= 256)
        uint16 outLength;
        uint16 outPointer;
    #else
        uint8 outLength;
        uint8 outPointer;
    #endif /* (CDC_MIDI_OUT_BUFF_SIZE >= 256) */

        /* Service the USB MIDI output endpoint. */
        if (CDC_OUT_BUFFER_FULL == CDC_GetEPState(CDC_midi_out_ep))
        {
        #if (CDC_MIDI_OUT_BUFF_SIZE >= 256)
            outLength = CDC_GetEPCount(CDC_midi_out_ep);
        #else
            outLength = (uint8)CDC_GetEPCount(CDC_midi_out_ep);
        #endif /* (CDC_MIDI_OUT_BUFF_SIZE >= 256) */

        #if (!CDC_EP_MANAGEMENT_DMA_AUTO)
            #if (CDC_MIDI_OUT_BUFF_SIZE >= 256)
                outLength = CDC_ReadOutEP(CDC_midi_out_ep,
                                                       CDC_midiOutBuffer, outLength);
            #else
                outLength = (uint8)CDC_ReadOutEP(CDC_midi_out_ep,
                                                              CDC_midiOutBuffer, (uint16) outLength);
            #endif /* (CDC_MIDI_OUT_BUFF_SIZE >= 256) */

            #if (CDC_EP_MANAGEMENT_DMA_MANUAL)
                /* Wait until DMA complete transferring data from OUT endpoint buffer. */
                while (CDC_OUT_BUFFER_FULL == CDC_GetEPState(CDC_midi_out_ep))
                {
                }

                /* Enable OUT endpoint for communication with host. */
                CDC_EnableOutEP(CDC_midi_out_ep);
            #endif /* (CDC_EP_MANAGEMENT_DMA_MANUAL) */
        #endif /* (!CDC_EP_MANAGEMENT_DMA_AUTO) */

            if (outLength >= CDC_EVENT_LENGTH)
            {
                outPointer = 0u;
                while (outPointer < outLength)
                {
                    /* In some OS OUT packet could be appended by nulls which could be skipped. */
                    if (CDC_midiOutBuffer[outPointer] == 0u)
                    {
                        break;
                    }

                /* Route USB MIDI to the External connection */
                #if (CDC_MIDI_EXT_MODE >= CDC_ONE_EXT_INTRF)
                    if ((CDC_midiOutBuffer[outPointer] & CDC_CABLE_MASK) ==
                         CDC_MIDI_CABLE_00)
                    {
                        CDC_MIDI1_ProcessUsbOut(&CDC_midiOutBuffer[outPointer]);
                    }
                    else if ((CDC_midiOutBuffer[outPointer] & CDC_CABLE_MASK) ==
                             CDC_MIDI_CABLE_01)
                    {
                    #if (CDC_MIDI_EXT_MODE >= CDC_TWO_EXT_INTRF)
                         CDC_MIDI2_ProcessUsbOut(&CDC_midiOutBuffer[outPointer]);
                    #endif /*  CDC_MIDI_EXT_MODE >= CDC_TWO_EXT_INTRF */
                    }
                    else
                    {
                        /* `#START CUSTOM_MIDI_OUT_EP_SERV` Place your code here */

                        /* `#END` */

                        #ifdef CDC_MIDI_OUT_EP_SERVICE_CALLBACK
                            CDC_MIDI_OUT_EP_Service_Callback();
                        #endif /* CDC_MIDI_OUT_EP_SERVICE_CALLBACK */
                    }
                #endif /* (CDC_MIDI_EXT_MODE >= CDC_ONE_EXT_INTRF) */

                    /* Process any local MIDI output functions */
                    CDC_callbackLocalMidiEvent(CDC_midiOutBuffer[outPointer] & CDC_CABLE_MASK,
                                                            &CDC_midiOutBuffer[outPointer + CDC_EVENT_BYTE1]);
                    outPointer += CDC_EVENT_LENGTH;
                }
            }

        #if (CDC_EP_MANAGEMENT_DMA_AUTO)
            /* Enable OUT endpoint for communication */
            CDC_EnableOutEP(CDC_midi_out_ep);
        #endif  /* (CDC_EP_MANAGEMENT_DMA_AUTO) */
        }
    }
#endif /* (CDC_MIDI_OUT_BUFF_SIZE > 0) */


#if (CDC_MIDI_IN_BUFF_SIZE > 0)
    /*******************************************************************************
    * Function Name: CDC_MIDI_IN_EP_Service
    ****************************************************************************//**
    *
    *  Services the USB MIDI IN endpoint. Non-blocking.
    *  Checks that previous packet was processed by HOST, otherwise service the
    *  input endpoint on the subsequent call. It is called from the
    *  CDC_MIDI_IN_Service() and from the
    *  CDC_PutUsbMidiIn() function.
    *
    * \globalvars
    *  CDC_midi_in_ep: Used as an IN endpoint number.
    *  CDC_midiInBuffer: Function loads the data from this buffer to
    *    the USB IN endpoint.
    *   CDC_midiInPointer: Cleared to zero when data are sent.
    *
    * \reentrant
    *  No
    *
    *******************************************************************************/
    void CDC_MIDI_IN_EP_Service(void) 
    {
        /* Service the USB MIDI input endpoint */
        /* Check that previous packet was processed by HOST, otherwise service the USB later */
        if (CDC_midiInPointer != 0u)
        {
            if(CDC_GetEPState(CDC_midi_in_ep) == CDC_EVENT_PENDING)
            {
            #if (CDC_EP_MANAGEMENT_DMA_AUTO)
                CDC_LoadInEP(CDC_midi_in_ep, NULL, (uint16)CDC_midiInPointer);
            #else
                CDC_LoadInEP(CDC_midi_in_ep, CDC_midiInBuffer,
                                                              (uint16) CDC_midiInPointer);
            #endif /* (CDC_EP_MANAGEMENT_DMA_AUTO) */

            /* Clear the midiInPointer. For DMA mode, clear this pointer in the ARB ISR when data are moved by DMA */
            #if (CDC_EP_MANAGEMENT_MANUAL)
                CDC_midiInPointer = 0u;
            #endif /* (CDC_EP_MANAGEMENT_MANUAL) */
            }
        }
    }


    /*******************************************************************************
    * Function Name: CDC_MIDI_IN_Service
    ****************************************************************************//**
    *
    *  This function services the traffic from the MIDI input ports (RX UART)
    *  and prepare data in USB MIDI IN endpoint buffer.
    *  Calls the CDC_MIDI_IN_EP_Service() function to sent the
    *  data from buffer to PC. Non-blocking. Should be called from main foreground
    *  task.
    *  This function is not protected from the reentrant calls. When it is required
    *  to use this function in UART RX ISR to guaranty low latency, care should be
    *  taken to protect from reentrant calls.
    *  In PSoC 3, if this function is called from an ISR, you must declare this
    *  function as re-entrant so that different variable storage space is
    *  created by the compiler. This is automatically taken care for PSoC 4 and
    *  PSoC 5LP devices by the compiler.
    *
    * \globalvars
    *
    *   CDC_midiInPointer: Cleared to zero when data are sent.
    *
    * \reentrant
    *  No
    *
    *******************************************************************************/
    void CDC_MIDI_IN_Service(void) 
    {
        /* Service the MIDI UART inputs until either both receivers have no more
        *  events or until the input endpoint buffer fills up.
        */
    #if (CDC_MIDI_EXT_MODE >= CDC_ONE_EXT_INTRF)
            uint8 m1 = 0u;
            uint8 m2 = 0u;

        if (0u == CDC_midiInPointer)
        {
            do
            {
                if (CDC_midiInPointer <= (CDC_MIDI_IN_BUFF_SIZE - CDC_EVENT_LENGTH))
                {
                    /* Check MIDI1 input port for a complete event */
                    m1 = CDC_MIDI1_GetEvent();
                    if (m1 != 0u)
                    {
                        CDC_PrepareInBuffer(m1, (uint8 *)&CDC_MIDI1_Event.msgBuff[0],
                                                                       CDC_MIDI1_Event.size, CDC_MIDI_CABLE_00);
                    }
                }

            #if (CDC_MIDI_EXT_MODE >= CDC_TWO_EXT_INTRF)
                if (CDC_midiInPointer <= (CDC_MIDI_IN_BUFF_SIZE - CDC_EVENT_LENGTH))
                {
                    /* Check MIDI2 input port for a complete event */
                    m2 = CDC_MIDI2_GetEvent();
                    if (m2 != 0u)
                    {
                        CDC_PrepareInBuffer(m2, (uint8 *)&CDC_MIDI2_Event.msgBuff[0],
                                                                       CDC_MIDI2_Event.size, CDC_MIDI_CABLE_01);
                    }
                }
            #endif /*  CDC_MIDI_EXT_MODE >= CDC_TWO_EXT_INTRF */
            }
            while((CDC_midiInPointer <= (CDC_MIDI_IN_BUFF_SIZE - CDC_EVENT_LENGTH)) &&
                  ((m1 != 0u) || (m2 != 0u)));
        }
    #endif /* (CDC_MIDI_EXT_MODE >= CDC_ONE_EXT_INTRF) */

        /* Service the USB MIDI input endpoint */
        CDC_MIDI_IN_EP_Service();
    }


    /***************************************************************************
    * Function Name: CDC_PutUsbMidiIn
    ************************************************************************//**
    *
    *  This function puts one MIDI message into the USB MIDI In endpoint buffer.
    *  This is a MIDI input message to the host. This function is used only if
    *  the device has internal MIDI input functionality.
    *  The CDC_MIDI_IN_Service() function should also be called to
    *  send the message from local buffer to the IN endpoint.
    *
    *  \param ic: The length of the MIDI message or command is described on the
    *  following table.
    *  Value          | Description
    *  ---------------|---------------------------------------------------------
    *  0              | No message (should never happen)
    *  1 - 3          | Complete MIDI message in midiMsg
    *  3 IN EP LENGTH | Complete SySEx message(without EOSEX byte) in midiMsg. The length is limited by the max BULK EP size(64)
    *  MIDI_SYSEX     | Start or continuation of SysEx message (put event bytes in midiMsg buffer)
    *  MIDI_EOSEX     | End of SysEx message (put event bytes in midiMsg buffer)
    *  MIDI_TUNEREQ   | Tune Request message (single byte system common message)
    *  0xF8 - 0xFF    | Single byte real-time message
    *
    *  \param midiMsg: pointer to MIDI message.
    *  \param cable:   cable number.
    *
    * \return
    *   Return Value          | Description
    *   ----------------------|-----------------------------------------
    *  CDC_TRUE  | Host is not ready to receive this message
    *  CDC_FALSE | Success transfer
    *
    * \globalvars
    *
    *  \ref CDC_midi_in_ep: MIDI IN endpoint number used for
    *        sending data.
    *
    *  \ref CDC_midiInPointer: Checked this variable to see if
    *        there is enough free space in the IN endpoint buffer. If buffer is
    *        full, initiate sending to PC.
    *
    * \reentrant
    *  No
    *
    ***************************************************************************/
    uint8 CDC_PutUsbMidiIn(uint8 ic, const uint8 midiMsg[], uint8 cable)
                                                                
    {
        uint8 retError = CDC_FALSE;

        /* Protect PrepareInBuffer() function from concurrent calls */
    #if (CDC_MIDI_EXT_MODE >= CDC_ONE_EXT_INTRF)
        MIDI1_UART_DisableRxInt();
        #if (CDC_MIDI_EXT_MODE >= CDC_TWO_EXT_INTRF)
            MIDI2_UART_DisableRxInt();
        #endif /* (CDC_MIDI_EXT_MODE >= CDC_TWO_EXT_INTRF) */
    #endif /* (CDC_MIDI_EXT_MODE >= CDC_ONE_EXT_INTRF) */

        if (CDC_midiInPointer >
                    (CDC_EP[CDC_midi_in_ep].bufferSize - CDC_EVENT_LENGTH))
        {
            CDC_MIDI_IN_EP_Service();
        }

        if (CDC_midiInPointer <=
                    (CDC_EP[CDC_midi_in_ep].bufferSize - CDC_EVENT_LENGTH))
        {
            if((ic < CDC_EVENT_LENGTH) || (ic >= CDC_MIDI_STATUS_MASK))
            {
                CDC_PrepareInBuffer(ic, midiMsg, ic, cable);
            }
            else /* Only SysEx message is greater than 4 bytes */
            {
                /* Convert SysEx message into midi message format */
                uint8 idx = 0u;
                do
                {
                    /* Process 3 bytes of message until 0-2 bytes are left. These bytes are handled by MIDI_EOSEX. */
                    CDC_PrepareInBuffer(CDC_MIDI_SYSEX, &midiMsg[idx],
                                                     CDC_EVENT_BYTE3, cable);

                    /* Move to next 3 bytes of message */
                    ic  -= CDC_EVENT_BYTE3;
                    idx += CDC_EVENT_BYTE3;

                    if (CDC_midiInPointer >
                        (CDC_EP[CDC_midi_in_ep].bufferSize - CDC_EVENT_LENGTH))
                    {
                        /* Load message into endpoint */
                        CDC_MIDI_IN_EP_Service();

                        if (CDC_midiInPointer >
                           (CDC_EP[CDC_midi_in_ep].bufferSize - CDC_EVENT_LENGTH))
                        {
                            /* Error condition. Host is not ready to receive this packet. */
                            retError = CDC_TRUE;
                            break;
                        }
                    }
                }
                while (ic >= CDC_EVENT_BYTE3);

                if (retError == CDC_FALSE)
                {
                    /* Handle end of message: valid size of messages is 0, 1 and 2 */
                    CDC_PrepareInBuffer(CDC_MIDI_EOSEX, &midiMsg[idx], ic, cable);
                }
            }
        }
        else
        {
            /* Error condition. Host is not ready to receive this packet. */
            retError = CDC_TRUE;
        }

    #if (CDC_MIDI_EXT_MODE >= CDC_ONE_EXT_INTRF)
        MIDI1_UART_EnableRxInt();
        #if (CDC_MIDI_EXT_MODE >= CDC_TWO_EXT_INTRF)
            MIDI2_UART_EnableRxInt();
        #endif /* (CDC_MIDI_EXT_MODE >= CDC_TWO_EXT_INTRF) */
    #endif /* (CDC_MIDI_EXT_MODE >= CDC_ONE_EXT_INTRF) */

        return (retError);
    }


    /*******************************************************************************
    * Function Name: CDC_PrepareInBuffer
    ****************************************************************************//**
    *
    *  Builds a USB MIDI event in the input endpoint buffer at the current pointer.
    *  Puts one MIDI message into the USB MIDI In endpoint buffer.
    *
    *  \param ic:   0 = No message (should never happen)
    *        1 - 3 = Complete MIDI message at pMdat[0]
    *        MIDI_SYSEX = Start or continuation of SysEx message
    *                     (put eventLen bytes in buffer)
    *        MIDI_EOSEX = End of SysEx message
    *                     (put eventLen bytes in buffer,
    *                      and append MIDI_EOSEX)
    *        MIDI_TUNEREQ = Tune Request message (single byte system common msg)
    *        0xf8 - 0xff = Single byte real-time message
    *
    *  \param srcBuff: pointer to MIDI data
    *  \param eventLen: number of bytes in MIDI event
    *  \param cable: MIDI source port number
    *
    * \globalvars
    *  CDC_midiInBuffer: This buffer is used for saving and combine the
    *    received from UART(s) and(or) generated internally by
    *    CDC_PutUsbMidiIn() function messages.
    *  CDC_midiInPointer: Used as an index for midiInBuffer to
    *     write data.
    *
    * \reentrant
    *  No
    *
    *******************************************************************************/
    void CDC_PrepareInBuffer(uint8 ic, const uint8 srcBuff[], uint8 eventLen, uint8 cable)
                                                                 
    {
        uint8 srcBuffZero;
        uint8 srcBuffOne;

        srcBuffZero = srcBuff[0u];
        srcBuffOne  = srcBuff[1u];

        if (ic >= (CDC_MIDI_STATUS_MASK | CDC_MIDI_SINGLE_BYTE_MASK))
        {
            CDC_midiInBuffer[CDC_midiInPointer] = CDC_SINGLE_BYTE | cable;
            CDC_midiInPointer++;
            CDC_midiInBuffer[CDC_midiInPointer] = ic;
            CDC_midiInPointer++;
            CDC_midiInBuffer[CDC_midiInPointer] = 0u;
            CDC_midiInPointer++;
            CDC_midiInBuffer[CDC_midiInPointer] = 0u;
            CDC_midiInPointer++;
        }
        else if((ic < CDC_EVENT_LENGTH) || (ic == CDC_MIDI_SYSEX))
        {
            if(ic == CDC_MIDI_SYSEX)
            {
                CDC_midiInBuffer[CDC_midiInPointer] = CDC_SYSEX | cable;
                CDC_midiInPointer++;
            }
            else if (srcBuffZero < CDC_MIDI_SYSEX)
            {
                CDC_midiInBuffer[CDC_midiInPointer] = (srcBuffZero >> 4u) | cable;
                CDC_midiInPointer++;
            }
            else if (srcBuffZero == CDC_MIDI_TUNEREQ)
            {
                CDC_midiInBuffer[CDC_midiInPointer] = CDC_1BYTE_COMMON | cable;
                CDC_midiInPointer++;
            }
            else if ((srcBuffZero == CDC_MIDI_QFM) || (srcBuffZero == CDC_MIDI_SONGSEL))
            {
                CDC_midiInBuffer[CDC_midiInPointer] = CDC_2BYTE_COMMON | cable;
                CDC_midiInPointer++;
            }
            else if (srcBuffZero == CDC_MIDI_SPP)
            {
                CDC_midiInBuffer[CDC_midiInPointer] = CDC_3BYTE_COMMON | cable;
                CDC_midiInPointer++;
            }
            else
            {
            }

            CDC_midiInBuffer[CDC_midiInPointer] = srcBuffZero;
            CDC_midiInPointer++;
            CDC_midiInBuffer[CDC_midiInPointer] = srcBuffOne;
            CDC_midiInPointer++;
            CDC_midiInBuffer[CDC_midiInPointer] = srcBuff[2u];
            CDC_midiInPointer++;
        }
        else if (ic == CDC_MIDI_EOSEX)
        {
            switch (eventLen)
            {
                case 0u:
                    CDC_midiInBuffer[CDC_midiInPointer] = CDC_SYSEX_ENDS_WITH1 | cable;
                    CDC_midiInPointer++;
                    CDC_midiInBuffer[CDC_midiInPointer] = CDC_MIDI_EOSEX;
                    CDC_midiInPointer++;
                    CDC_midiInBuffer[CDC_midiInPointer] = 0u;
                    CDC_midiInPointer++;
                    CDC_midiInBuffer[CDC_midiInPointer] = 0u;
                    CDC_midiInPointer++;
                    break;
                case 1u:
                    CDC_midiInBuffer[CDC_midiInPointer] = CDC_SYSEX_ENDS_WITH2 | cable;
                    CDC_midiInPointer++;
                    CDC_midiInBuffer[CDC_midiInPointer] = srcBuffZero;
                    CDC_midiInPointer++;
                    CDC_midiInBuffer[CDC_midiInPointer] = CDC_MIDI_EOSEX;
                    CDC_midiInPointer++;
                    CDC_midiInBuffer[CDC_midiInPointer] = 0u;
                    CDC_midiInPointer++;
                    break;
                case 2u:
                    CDC_midiInBuffer[CDC_midiInPointer] = CDC_SYSEX_ENDS_WITH3 | cable;
                    CDC_midiInPointer++;
                    CDC_midiInBuffer[CDC_midiInPointer] = srcBuffZero;
                    CDC_midiInPointer++;
                    CDC_midiInBuffer[CDC_midiInPointer] = srcBuffOne;
                    CDC_midiInPointer++;
                    CDC_midiInBuffer[CDC_midiInPointer] = CDC_MIDI_EOSEX;
                    CDC_midiInPointer++;
                    break;
                default:
                    break;
            }
        }
        else
        {
        }
    }

#endif /* (CDC_MIDI_IN_BUFF_SIZE > 0) */


/* The implementation for external serial input and output connections
*  to route USB MIDI data to and from those connections.
*/
#if (CDC_MIDI_EXT_MODE >= CDC_ONE_EXT_INTRF)
    /*******************************************************************************
    * Function Name: CDC_MIDI_InitInterface
    ****************************************************************************//**
    *
    *  Initializes MIDI variables and starts the UART(s) hardware block(s).
    *
    * \sideeffect
    *  Change the priority of the UART(s) TX interrupts to be higher than the
    *  default EP ISR priority.
    *
    * \globalvars
    *   CDC_MIDI_Event: initialized to zero.
    *   CDC_MIDI_TxRunStat: initialized to zero.
    *
    *******************************************************************************/
    void CDC_MIDI_InitInterface(void) 
    {
        CDC_MIDI1_Event.length  = 0u;
        CDC_MIDI1_Event.count   = 0u;
        CDC_MIDI1_Event.size    = 0u;
        CDC_MIDI1_Event.runstat = 0u;
        CDC_MIDI1_TxRunStat     = 0u;
        CDC_MIDI1_InqFlags      = 0u;

        /* Start UART block */
        MIDI1_UART_Start();

        /* Change the priority of the UART TX and RX interrupt */
        CyIntSetPriority(MIDI1_UART_TX_VECT_NUM, CDC_CUSTOM_UART_TX_PRIOR_NUM);
        CyIntSetPriority(MIDI1_UART_RX_VECT_NUM, CDC_CUSTOM_UART_RX_PRIOR_NUM);

    #if (CDC_MIDI_EXT_MODE >= CDC_TWO_EXT_INTRF)
        CDC_MIDI2_Event.length  = 0u;
        CDC_MIDI2_Event.count   = 0u;
        CDC_MIDI2_Event.size    = 0u;
        CDC_MIDI2_Event.runstat = 0u;
        CDC_MIDI2_TxRunStat     = 0u;
        CDC_MIDI2_InqFlags      = 0u;

        /* Start second UART block */
        MIDI2_UART_Start();

        /* Change the priority of the UART TX interrupt */
        CyIntSetPriority(MIDI2_UART_TX_VECT_NUM, CDC_CUSTOM_UART_TX_PRIOR_NUM);
        CyIntSetPriority(MIDI2_UART_RX_VECT_NUM, CDC_CUSTOM_UART_RX_PRIOR_NUM);
    #endif /* (CDC_MIDI_EXT_MODE >= CDC_TWO_EXT_INTRF) */

        /* `#START MIDI_INIT_CUSTOM` Init other extended UARTs here */

        /* `#END` */

    #ifdef CDC_MIDI_INIT_CALLBACK
        CDC_MIDI_Init_Callback();
    #endif /* (CDC_MIDI_INIT_CALLBACK) */
    }


    /*******************************************************************************
    * Function Name: CDC_ProcessMidiIn
    ****************************************************************************//**
    *
    *  Processes one byte of incoming MIDI data.
    *
    *   mData = current MIDI input data byte
    *   *rxStat = pointer to a MIDI_RX_STATUS structure
    *
    * \return
    *   0, if no complete message
    *   1 - 4, if message complete
    *   MIDI_SYSEX, if start or continuation of system exclusive
    *   MIDI_EOSEX, if end of system exclusive
    *   0xf8 - 0xff, if single byte real time message
    *
    *******************************************************************************/
    uint8 CDC_ProcessMidiIn(uint8 mData, CDC_MIDI_RX_STATUS *rxStat)
                                                                
    {
        uint8 midiReturn = 0u;

        /* Check for a MIDI status byte.  All status bytes, except real time messages,
        *  which are a single byte, force the start of a new buffer cycle.
        */
        if ((mData & CDC_MIDI_STATUS_BYTE_MASK) != 0u)
        {
            if ((mData & CDC_MIDI_STATUS_MASK) == CDC_MIDI_STATUS_MASK)
            {
                if ((mData & CDC_MIDI_SINGLE_BYTE_MASK) != 0u) /* System Real-Time Messages(single byte) */
                {
                    midiReturn = mData;
                }
                else                              /* System Common Messages */
                {
                    switch (mData)
                    {
                        case CDC_MIDI_SYSEX:
                            rxStat->msgBuff[0u] = CDC_MIDI_SYSEX;
                            rxStat->runstat = CDC_MIDI_SYSEX;
                            rxStat->count = 1u;
                            rxStat->length = 3u;
                            break;
                        case CDC_MIDI_EOSEX:
                            rxStat->runstat = 0u;
                            rxStat->size = rxStat->count;
                            rxStat->count = 0u;
                            midiReturn = CDC_MIDI_EOSEX;
                            break;
                        case CDC_MIDI_SPP:
                            rxStat->msgBuff[0u] = CDC_MIDI_SPP;
                            rxStat->runstat = 0u;
                            rxStat->count = 1u;
                            rxStat->length = 3u;
                            break;
                        case CDC_MIDI_SONGSEL:
                            rxStat->msgBuff[0u] = CDC_MIDI_SONGSEL;
                            rxStat->runstat = 0u;
                            rxStat->count = 1u;
                            rxStat->length = 2u;
                            break;
                        case CDC_MIDI_QFM:
                            rxStat->msgBuff[0u] = CDC_MIDI_QFM;
                            rxStat->runstat = 0u;
                            rxStat->count = 1u;
                            rxStat->length = 2u;
                            break;
                        case CDC_MIDI_TUNEREQ:
                            rxStat->msgBuff[0u] = CDC_MIDI_TUNEREQ;
                            rxStat->runstat = 0u;
                            rxStat->size = 1u;
                            rxStat->count = 0u;
                            midiReturn = rxStat->size;
                            break;
                        default:
                            break;
                    }
                }
            }
            else /* Channel Messages */
            {
                rxStat->msgBuff[0u] = mData;
                rxStat->runstat = mData;
                rxStat->count = 1u;
                switch (mData & CDC_MIDI_STATUS_MASK)
                {
                    case CDC_MIDI_NOTE_OFF:
                    case CDC_MIDI_NOTE_ON:
                    case CDC_MIDI_POLY_KEY_PRESSURE:
                    case CDC_MIDI_CONTROL_CHANGE:
                    case CDC_MIDI_PITCH_BEND_CHANGE:
                        rxStat->length = 3u;
                        break;
                    case CDC_MIDI_PROGRAM_CHANGE:
                    case CDC_MIDI_CHANNEL_PRESSURE:
                        rxStat->length = 2u;
                        break;
                    default:
                        rxStat->runstat = 0u;
                        rxStat->count = 0u;
                        break;
                }
            }
        }

        /* Otherwise, it's a data byte */
        else
        {
            if (rxStat->runstat == CDC_MIDI_SYSEX)
            {
                rxStat->msgBuff[rxStat->count] = mData;
                rxStat->count++;
                if (rxStat->count >= rxStat->length)
                {
                    rxStat->size = rxStat->count;
                    rxStat->count = 0u;
                    midiReturn = CDC_MIDI_SYSEX;
                }
            }
            else if (rxStat->count > 0u)
            {
                rxStat->msgBuff[rxStat->count] = mData;
                rxStat->count++;
                if (rxStat->count >= rxStat->length)
                {
                    rxStat->size = rxStat->count;
                    rxStat->count = 0u;
                    midiReturn = rxStat->size;
                }
            }
            else if (rxStat->runstat != 0u)
            {
                rxStat->msgBuff[0u] = rxStat->runstat;
                rxStat->msgBuff[1u] = mData;
                rxStat->count = 2u;
                switch (rxStat->runstat & CDC_MIDI_STATUS_MASK)
                {
                    case CDC_MIDI_NOTE_OFF:
                    case CDC_MIDI_NOTE_ON:
                    case CDC_MIDI_POLY_KEY_PRESSURE:
                    case CDC_MIDI_CONTROL_CHANGE:
                    case CDC_MIDI_PITCH_BEND_CHANGE:
                        rxStat->length = 3u;
                        break;
                    case CDC_MIDI_PROGRAM_CHANGE:
                    case CDC_MIDI_CHANNEL_PRESSURE:
                        rxStat->size = rxStat->count;
                        rxStat->count = 0u;
                        midiReturn = rxStat->size;
                        break;
                    default:
                        rxStat->count = 0u;
                    break;
                }
            }
            else
            {
            }
        }
        return (midiReturn);
    }


    /*******************************************************************************
    * Function Name: CDC_MIDI1_GetEvent
    ****************************************************************************//**
    *
    *  Checks for incoming MIDI data, calls the MIDI event builder if so.
    *  Returns either empty or with a complete event.
    *
    * \return
    *   0, if no complete message
    *   1 - 4, if message complete
    *   MIDI_SYSEX, if start or continuation of system exclusive
    *   MIDI_EOSEX, if end of system exclusive
    *   0xf8 - 0xff, if single byte real time message
    *
    * \globalvars
    *  CDC_MIDI1_Event: RX status structure used to parse received
    *    data.
    *
    *******************************************************************************/
    uint8 CDC_MIDI1_GetEvent(void) 
    {
        uint8 msgRtn = 0u;
        uint8 rxData;
        #if (MIDI1_UART_RXBUFFERSIZE >= 256u)
            uint16 rxBufferRead;
            #if (CY_PSOC3) /* This local variable is required only for PSOC3 and large buffer */
                uint16 rxBufferWrite;
            #endif /* (CY_PSOC3) */
        #else
            uint8 rxBufferRead;
        #endif /* (MIDI1_UART_RXBUFFERSIZE >= 256u) */

        uint8 rxBufferLoopDetect;
        /* Read buffer loop condition to the local variable */
        rxBufferLoopDetect = MIDI1_UART_rxBufferLoopDetect;

        if ((MIDI1_UART_rxBufferRead != MIDI1_UART_rxBufferWrite) || (rxBufferLoopDetect != 0u))
        {
            /* Protect variables that could change on interrupt by disabling Rx interrupt.*/
            #if ((MIDI1_UART_RXBUFFERSIZE >= 256u) && (CY_PSOC3))
                CyIntDisable(MIDI1_UART_RX_VECT_NUM);
            #endif /* ((MIDI1_UART_RXBUFFERSIZE >= 256u) && (CY_PSOC3)) */

            rxBufferRead = MIDI1_UART_rxBufferRead;
            #if ((MIDI1_UART_RXBUFFERSIZE >= 256u) && (CY_PSOC3))
                rxBufferWrite = MIDI1_UART_rxBufferWrite;
                CyIntEnable(MIDI1_UART_RX_VECT_NUM);
            #endif /* ((MIDI1_UART_RXBUFFERSIZE >= 256u) && (CY_PSOC3)) */

            /* Stay here until either the buffer is empty or we have a complete message
            *  in the message buffer. Note that we must use a temporary buffer pointer
            *  since it takes two instructions to increment with a wrap, and we can't
            *  risk doing that with the real pointer and getting an interrupt in between
            *  instructions.
            */

            #if ((MIDI1_UART_RXBUFFERSIZE >= 256u) && (CY_PSOC3))
                while ( ((rxBufferRead != rxBufferWrite) || (rxBufferLoopDetect != 0u)) && (msgRtn == 0u) )
            #else
                while ( ((rxBufferRead != MIDI1_UART_rxBufferWrite) || (rxBufferLoopDetect != 0u)) && (msgRtn == 0u) )
            #endif /*  ((MIDI1_UART_RXBUFFERSIZE >= 256u) && (CY_PSOC3)) */
                {
                    rxData = MIDI1_UART_rxBuffer[rxBufferRead];
                    /* Increment pointer with a wrap */
                    rxBufferRead++;
                    if (rxBufferRead >= MIDI1_UART_RXBUFFERSIZE)
                    {
                        rxBufferRead = 0u;
                    }

                    /* If loop condition was set - update real read buffer pointer
                    *  to avoid overflow status
                    */
                    if (rxBufferLoopDetect != 0u )
                    {
                        MIDI1_UART_rxBufferLoopDetect = 0u;
                    #if ((MIDI1_UART_RXBUFFERSIZE >= 256u) && (CY_PSOC3))
                        CyIntDisable(MIDI1_UART_RX_VECT_NUM);
                    #endif /*  MIDI1_UART_RXBUFFERSIZE >= 256 */

                        MIDI1_UART_rxBufferRead = rxBufferRead;
                    #if ((MIDI1_UART_RXBUFFERSIZE >= 256u) && (CY_PSOC3))
                        CyIntEnable(MIDI1_UART_RX_VECT_NUM);
                    #endif /*  MIDI1_UART_RXBUFFERSIZE >= 256 */
                    }

                    msgRtn = CDC_ProcessMidiIn(rxData,
                                                    (CDC_MIDI_RX_STATUS *)&CDC_MIDI1_Event);

                    /* Read buffer loop condition to the local variable */
                    rxBufferLoopDetect = MIDI1_UART_rxBufferLoopDetect;
                }

            /* Finally, update the real output pointer, then return with
            *  an indication as to whether there's a complete message in the buffer.
            */
        #if ((MIDI1_UART_RXBUFFERSIZE >= 256u) && (CY_PSOC3))
            CyIntDisable(MIDI1_UART_RX_VECT_NUM);
        #endif /* ((MIDI1_UART_RXBUFFERSIZE >= 256u) && (CY_PSOC3)) */

        MIDI1_UART_rxBufferRead = rxBufferRead;
        #if ((MIDI1_UART_RXBUFFERSIZE >= 256u) && (CY_PSOC3))
            CyIntEnable(MIDI1_UART_RX_VECT_NUM);
        #endif /* ((MIDI1_UART_RXBUFFERSIZE >= 256u) && (CY_PSOC3)) */
        }

        return (msgRtn);
    }


    /*******************************************************************************
    * Function Name: CDC_MIDI1_ProcessUsbOut
    ****************************************************************************//**
    *
    *  Process a USB MIDI output event.
    *  Puts data into the MIDI TX output buffer.
    *
    *  \param *epBuf: pointer on MIDI event.
    *
    * \globalvars
    *  CDC_MIDI1_TxRunStat: This variable used to save the MIDI
    *    status byte and skip to send the repeated status byte in subsequent event.
    *  CDC_MIDI1_InqFlags: The following flags are set when SysEx
    *    message comes.
    *    CDC_INQ_SYSEX_FLAG: Non-Real Time SySEx message received.
    *    CDC_INQ_IDENTITY_REQ_FLAG: Identity Request received.
    *      This bit should be cleared by user when Identity Reply message generated.
    *
    *******************************************************************************/
    void CDC_MIDI1_ProcessUsbOut(const uint8 epBuf[])
                                                            
    {
        uint8 cmd;
        uint8 len;
        uint8 i;

        /* User code is required at the beginning of the procedure */
        /* `#START MIDI1_PROCESS_OUT_BEGIN` */

        /* `#END` */

    #ifdef CDC_MIDI1_PROCESS_USB_OUT_ENTRY_CALLBACK
        CDC_MIDI1_ProcessUsbOut_EntryCallback();
    #endif /* (CDC_MIDI1_PROCESS_USB_OUT_ENTRY_CALLBACK) */

        cmd = epBuf[CDC_EVENT_BYTE0] & CDC_CIN_MASK;

        if ((cmd != CDC_RESERVED0) && (cmd != CDC_RESERVED1))
        {
            len = CDC_MIDI_SIZE[cmd];
            i = CDC_EVENT_BYTE1;
            /* Universal System Exclusive message parsing */
            if (cmd == CDC_SYSEX)
            {
                if ((epBuf[CDC_EVENT_BYTE1] == CDC_MIDI_SYSEX) &&
                    (epBuf[CDC_EVENT_BYTE2] == CDC_MIDI_SYSEX_NON_REAL_TIME))
                {
                    /* Non-Real Time SySEx starts */
                    CDC_MIDI1_InqFlags |= CDC_INQ_SYSEX_FLAG;
                }
                else
                {
                    CDC_MIDI1_InqFlags &= (uint8)~CDC_INQ_SYSEX_FLAG;
                }
            }
            else if (cmd == CDC_SYSEX_ENDS_WITH1)
            {
                CDC_MIDI1_InqFlags &= (uint8)~CDC_INQ_SYSEX_FLAG;
            }
            else if (cmd == CDC_SYSEX_ENDS_WITH2)
            {
                CDC_MIDI1_InqFlags &= (uint8)~CDC_INQ_SYSEX_FLAG;
            }
            else if (cmd == CDC_SYSEX_ENDS_WITH3)
            {
                /* Identify Request support */
                if ((CDC_MIDI1_InqFlags & CDC_INQ_SYSEX_FLAG) != 0u)
                {
                    CDC_MIDI1_InqFlags &= (uint8)~CDC_INQ_SYSEX_FLAG;
                    if ((epBuf[CDC_EVENT_BYTE1] == CDC_MIDI_SYSEX_GEN_INFORMATION) &&
                        (epBuf[CDC_EVENT_BYTE2] == CDC_MIDI_SYSEX_IDENTITY_REQ))
                    {
                        /* Set the flag about received the Identity Request.
                        *  The Identity Reply message may be send by user code.
                        */
                        CDC_MIDI1_InqFlags |= CDC_INQ_IDENTITY_REQ_FLAG;
                    }
                }
            }
            else /* Do nothing for other command */
            {
            }

            /* Running Status for Voice and Mode messages only. */
            if ((cmd >= CDC_NOTE_OFF) && (cmd <= CDC_PITCH_BEND_CHANGE))
            {
                if (CDC_MIDI1_TxRunStat == epBuf[CDC_EVENT_BYTE1])
                {
                    /* Skip the repeated Status byte */
                    i++;
                }
                else
                {
                    /* Save Status byte for next event */
                    CDC_MIDI1_TxRunStat = epBuf[CDC_EVENT_BYTE1];
                }
            }
            else
            {
                /* Clear Running Status */
                CDC_MIDI1_TxRunStat = 0u;
            }

            /* Puts data into the MIDI TX output buffer.*/
            do
            {
                MIDI1_UART_PutChar(epBuf[i]);
                i++;
            }
            while (i <= len);
        }

        /* User code is required at the end of the procedure */
        /* `#START MIDI1_PROCESS_OUT_END` */

        /* `#END` */

    #ifdef CDC_MIDI1_PROCESS_USB_OUT_EXIT_CALLBACK
        CDC_MIDI1_ProcessUsbOut_ExitCallback();
    #endif /* (CDC_MIDI1_PROCESS_USB_OUT_EXIT_CALLBACK) */
    }


#if (CDC_MIDI_EXT_MODE >= CDC_TWO_EXT_INTRF)
    /*******************************************************************************
    * Function Name: CDC_MIDI2_GetEvent
    ****************************************************************************//**
    *
    *  Checks for incoming MIDI data, calls the MIDI event builder if so.
    *  Returns either empty or with a complete event.
    *
    * \return
    *   0, if no complete message
    *   1 - 4, if message complete
    *   MIDI_SYSEX, if start or continuation of system exclusive
    *   MIDI_EOSEX, if end of system exclusive
    *   0xf8 - 0xff, if single byte real time message
    *
    * \globalvars
    *  CDC_MIDI2_Event: RX status structure used to parse received
    *    data.
    *
    *******************************************************************************/
    uint8 CDC_MIDI2_GetEvent(void) 
    {
        uint8 msgRtn = 0u;
        uint8 rxData;

        #if (MIDI2_UART_RXBUFFERSIZE >= 256u)
            uint16 rxBufferRead;
            #if (CY_PSOC3) /* This local variable required only for PSOC3 and large buffer */
                uint16 rxBufferWrite;
            #endif /* (CY_PSOC3) */
        #else
            uint8 rxBufferRead;
        #endif /* (MIDI2_UART_RXBUFFERSIZE >= 256) */

        uint8 rxBufferLoopDetect;
        /* Read buffer loop condition to the local variable */
        rxBufferLoopDetect = MIDI2_UART_rxBufferLoopDetect;

        if ( (MIDI2_UART_rxBufferRead != MIDI2_UART_rxBufferWrite) || (rxBufferLoopDetect != 0u) )
        {
            /* Protect variables that could change on interrupt by disabling Rx interrupt.*/
            #if ((MIDI2_UART_RXBUFFERSIZE >= 256u) && (CY_PSOC3))
                CyIntDisable(MIDI2_UART_RX_VECT_NUM);
            #endif /* ((MIDI2_UART_RXBUFFERSIZE >= 256u) && (CY_PSOC3)) */
            rxBufferRead = MIDI2_UART_rxBufferRead;
            #if ((MIDI2_UART_RXBUFFERSIZE >= 256u) && (CY_PSOC3))
                rxBufferWrite = MIDI2_UART_rxBufferWrite;
                CyIntEnable(MIDI2_UART_RX_VECT_NUM);
            #endif /* ((MIDI2_UART_RXBUFFERSIZE >= 256u) && (CY_PSOC3)) */

            /* Stay here until either the buffer is empty or we have a complete message
            *  in the message buffer. Note that we must use a temporary output pointer to
            *  since it takes two instructions to increment with a wrap, and we can't
            *  risk doing that with the real pointer and getting an interrupt in between
            *  instructions.
            */

            #if ((MIDI2_UART_RXBUFFERSIZE >= 256u) && (CY_PSOC3))
                while ( ((rxBufferRead != rxBufferWrite) || (rxBufferLoopDetect != 0u)) && (msgRtn == 0u) )
            #else
                while ( ((rxBufferRead != MIDI2_UART_rxBufferWrite) || (rxBufferLoopDetect != 0u)) && (msgRtn == 0u) )
            #endif /* ((MIDI2_UART_RXBUFFERSIZE >= 256u) && (CY_PSOC3)) */
                {
                    rxData = MIDI2_UART_rxBuffer[rxBufferRead];
                    rxBufferRead++;
                    if(rxBufferRead >= MIDI2_UART_RXBUFFERSIZE)
                    {
                        rxBufferRead = 0u;
                    }

                    /* If loop condition was set - update real read buffer pointer
                    *  to avoid overflow status
                    */
                    if (rxBufferLoopDetect != 0u)
                    {
                        MIDI2_UART_rxBufferLoopDetect = 0u;
                    #if ((MIDI2_UART_RXBUFFERSIZE >= 256u) && (CY_PSOC3))
                        CyIntDisable(MIDI2_UART_RX_VECT_NUM);
                    #endif /* ((MIDI2_UART_RXBUFFERSIZE >= 256u) && (CY_PSOC3)) */

                        MIDI2_UART_rxBufferRead = rxBufferRead;
                    #if ((MIDI2_UART_RXBUFFERSIZE >= 256u) && (CY_PSOC3))
                        CyIntEnable(MIDI2_UART_RX_VECT_NUM);
                    #endif /* ((MIDI2_UART_RXBUFFERSIZE >= 256u) && (CY_PSOC3)) */
                    }

                    msgRtn = CDC_ProcessMidiIn(rxData,
                                                    (CDC_MIDI_RX_STATUS *)&CDC_MIDI2_Event);

                    /* Read buffer loop condition to the local variable */
                    rxBufferLoopDetect = MIDI2_UART_rxBufferLoopDetect;
                }

            /* Finally, update the real output pointer, then return with
            *  an indication as to whether there's a complete message in the buffer.
            */
        #if ((MIDI2_UART_RXBUFFERSIZE >= 256u) && (CY_PSOC3))
            CyIntDisable(MIDI2_UART_RX_VECT_NUM);
        #endif /* ((MIDI2_UART_RXBUFFERSIZE >= 256u) && (CY_PSOC3)) */

            MIDI2_UART_rxBufferRead = rxBufferRead;
        #if ((MIDI2_UART_RXBUFFERSIZE >= 256u) && (CY_PSOC3))
            CyIntEnable(MIDI2_UART_RX_VECT_NUM);
        #endif /* ((MIDI2_UART_RXBUFFERSIZE >= 256u) && (CY_PSOC3)) */
        }

        return (msgRtn);
    }


    /*******************************************************************************
    * Function Name: CDC_MIDI2_ProcessUsbOut
    ****************************************************************************//**
    *
    *  Process a USB MIDI output event.
    *  Puts data into the MIDI TX output buffer.
    *
    *  \param *epBuf: pointer on MIDI event.
    *
    * \globalvars
    *  CDC_MIDI2_TxRunStat: This variable used to save the MIDI
    *    status byte and skip to send the repeated status byte in subsequent event.
    *  CDC_MIDI2_InqFlags: The following flags are set when SysEx
    *    message comes.
    *  CDC_INQ_SYSEX_FLAG: Non-Real Time SySEx message received.
    *  CDC_INQ_IDENTITY_REQ_FLAG: Identity Request received.
    *    This bit should be cleared by user when Identity Reply message generated.
    *
    *******************************************************************************/
    void CDC_MIDI2_ProcessUsbOut(const uint8 epBuf[])
                                                            
    {
        uint8 cmd;
        uint8 len;
        uint8 i;

        /* User code is required at the beginning of the procedure */
        /* `#START MIDI2_PROCESS_OUT_START` */

        /* `#END` */

    #ifdef CDC_MIDI2_PROCESS_USB_OUT_ENTRY_CALLBACK
        CDC_MIDI2_ProcessUsbOut_EntryCallback();
    #endif /* (CDC_MIDI2_PROCESS_USB_OUT_ENTRY_CALLBACK) */

        cmd = epBuf[CDC_EVENT_BYTE0] & CDC_CIN_MASK;

        if ((cmd != CDC_RESERVED0) && (cmd != CDC_RESERVED1))
        {
            len = CDC_MIDI_SIZE[cmd];
            i = CDC_EVENT_BYTE1;

            /* Universal System Exclusive message parsing */
            if(cmd == CDC_SYSEX)
            {
                if((epBuf[CDC_EVENT_BYTE1] == CDC_MIDI_SYSEX) &&
                   (epBuf[CDC_EVENT_BYTE2] == CDC_MIDI_SYSEX_NON_REAL_TIME))
                {
                    /* SySEx starts */
                    CDC_MIDI2_InqFlags |= CDC_INQ_SYSEX_FLAG;
                }
                else
                {
                    CDC_MIDI2_InqFlags &= (uint8)~CDC_INQ_SYSEX_FLAG;
                }
            }
            else if(cmd == CDC_SYSEX_ENDS_WITH1)
            {
                CDC_MIDI2_InqFlags &= (uint8)~CDC_INQ_SYSEX_FLAG;
            }
            else if(cmd == CDC_SYSEX_ENDS_WITH2)
            {
                CDC_MIDI2_InqFlags &= (uint8)~CDC_INQ_SYSEX_FLAG;
            }
            else if(cmd == CDC_SYSEX_ENDS_WITH3)
            {
                /* Identify Request support */
                if ((CDC_MIDI2_InqFlags & CDC_INQ_SYSEX_FLAG) != 0u)
                {
                    CDC_MIDI2_InqFlags &= (uint8)~CDC_INQ_SYSEX_FLAG;

                    if((epBuf[CDC_EVENT_BYTE1] == CDC_MIDI_SYSEX_GEN_INFORMATION) &&
                       (epBuf[CDC_EVENT_BYTE2] == CDC_MIDI_SYSEX_IDENTITY_REQ))
                    {   /* Set the flag about received the Identity Request.
                        *  The Identity Reply message may be send by user code.
                        */
                        CDC_MIDI2_InqFlags |= CDC_INQ_IDENTITY_REQ_FLAG;
                    }
                }
            }
            else /* Do nothing for other command */
            {
            }

            /* Running Status for Voice and Mode messages only. */
            if ((cmd >= CDC_NOTE_OFF) && ( cmd <= CDC_PITCH_BEND_CHANGE))
            {
                if (CDC_MIDI2_TxRunStat == epBuf[CDC_EVENT_BYTE1])
                {   /* Skip the repeated Status byte */
                    i++;
                }
                else
                {   /* Save Status byte for next event */
                    CDC_MIDI2_TxRunStat = epBuf[CDC_EVENT_BYTE1];
                }
            }
            else
            {   /* Clear Running Status */
                CDC_MIDI2_TxRunStat = 0u;
            }

            /* Puts data into the MIDI TX output buffer.*/
            do
            {
                MIDI2_UART_PutChar(epBuf[i]);
                i++;
            }
            while (i <= len);
        }

        /* User code is required at the end of the procedure */
        /* `#START MIDI2_PROCESS_OUT_END` */

        /* `#END` */

    #ifdef CDC_MIDI2_PROCESS_USB_OUT_EXIT_CALLBACK
        CDC_MIDI2_ProcessUsbOut_ExitCallback();
    #endif /* (CDC_MIDI2_PROCESS_USB_OUT_EXIT_CALLBACK) */
    }
#endif /* (CDC_MIDI_EXT_MODE >= CDC_TWO_EXT_INTRF) */
#endif /* (CDC_MIDI_EXT_MODE >= CDC_ONE_EXT_INTRF) */

#endif  /*  (CDC_ENABLE_MIDI_API != 0u) */


/* `#START MIDI_FUNCTIONS` Place any additional functions here */

/* `#END` */

#endif  /* defined(CDC_ENABLE_MIDI_STREAMING) */


/* [] END OF FILE */
