/*
  USBSerial.cpp

  Copyright (c) 2023, Magawin
  Original code (pre-library): Copyright (c) 2011, Peter Barrett

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "USBSerial.h"
#include "MG32x02z.h"
#include "MG32x02z_USBD_API.h"
#include "MG32x02z_USBD_USBSerialDescriptor.h"
#include "USBSerial_API.h"


#if defined(USBCON)

#define COM_SYS_FREQ                       CONF_CK_APB_FREQ              /*!< System clock sourec frequence.*/


#ifdef __cplusplus
 extern "C" {
#endif



void API_UsbSerial_SetUARTState(void)
{
    USBSerial.SetUARTState();
}




void API_UsbSerial_GetLineCoding(uint8_t* gLineCodingBuf)
{
    USBSerial.GetLineCoding(gLineCodingBuf);
}

void API_UsbSerial_SetControlLineState(uint8_t* sControlLineStateBuf)
{
    USBSerial.SetControlLineState(sControlLineStateBuf);
}

uint32_t API_UsbSerial_SetLineCoding(uint8_t* sLineCodingBuf)
{
    return USBSerial.SetLineCoding(sLineCodingBuf);
}



void API_UsbSerial_SendBreak(uint8_t* SendBreakBuf)
{
    USBSerial.SendBreak(SendBreakBuf);
}

void API_UsbSerial_ReceiveDownstreamData()
{
    USBSerial.ReceiveDownstreamData();
}


#if 0

void API_UsbSerial_SetDataUpstream_Busy( uint8_t State )
{
    USBSerial.m_pUsbCom->COM_USB_DataUpstream_Busy = State;
}

void API_UsbSerial_SetUpstreamBusyStatue( uint8_t State )
{
    USBSerial.m_pUsbCom->COM_USB_StatusUpstream_Busy = State;
}

void API_UsbSerial_SetDownstreamBusyStatue( uint8_t State )
{
    USBSerial.m_pUsbCom->COM_USB_DataDownstream_Busy = State;
}
#endif




COM_TypeDef COM;  


#ifdef __cplusplus
}
#endif


/*
    uint8_t         m_Usb__OUTUpstreamBuf[COM_DATAUPSTREAM_BUFFER_SIZE]; 
    uint8_t         m_Usb__INUpstreamBuf[COM_DATAUPSTREAM_BUFFER_SIZE]; 
    uint8_t         m_Usb__DownstramBuf[COM_DATADOWNSTREAM_BUFFER_SIZE];
*/

/*
size_t USBSerial_::write(uint8_t *buffer, size_t size)
{
    return write((const uint8_t *)buffer, size) ;
}
*/
uint32_t USBSerial_::SetLineCoding(uint8_t* sLineCodingBuf)
{
   
    //=========================================================
    //Decode set LineCoding parameter.
    m_pUsbCom->LineCoding.BaudRate.B[0] = sLineCodingBuf[0];                        /*!< Baud-Rate [3:0] */
    m_pUsbCom->LineCoding.BaudRate.B[1] = sLineCodingBuf[1];
    m_pUsbCom->LineCoding.BaudRate.B[2] = sLineCodingBuf[2];
    m_pUsbCom->LineCoding.BaudRate.B[3] = sLineCodingBuf[3];
    m_pUsbCom->LineCoding.StopBit       = sLineCodingBuf[4];                        /*!< Stop bit        */
    m_pUsbCom->LineCoding.Parity        = sLineCodingBuf[5];                        /*!< Parity bit      */
    m_pUsbCom->LineCoding.DataBit       = sLineCodingBuf[6];                        /*!< Data bit        */
    m_pUsbCom->LineCoding.Flag          = SET;                                          
    
    //=========================================================
    //COM Relationship Control Parameter Default Inital.
    m_pUsbCom->COM_USB_DataDownstream_Busy      = 0;
    m_pUsbCom->COM_USB_DataUpstream_Busy        = 0;
    m_pUsbCom->COM_USB_StatusUpstream_Busy      = 0;
    m_pUsbCom->COM_USB_DataDownstream_Size      = 0;
    m_pUsbCom->COM_USB_DataUpstream_OverrunFlag = 0;

    
    //m_UsbWrite_In = 0;
    //m_UsbWrite_Out = 0;
    //m_UsbWrite_Cnt = 0;
    
    m_UsbRead_In = 0;
    m_UsbRead_Out = 0;
    m_UsbRead_Cnt = 0;
/*
    //=========================================================
    //Buffer Control Inital 
    m_Usb_pOutUpstreamBuf = 0;
    m_Usb_pInUpstreamBuf  = 0;
    m_Usb_UpstreamBufCnt  = 0;
*/

    return( COM_SUCCESS);
}

void USBSerial_::GetLineCoding(uint8_t* gLineCodingBuf)
{
    gLineCodingBuf[0] = m_pUsbCom->LineCoding.BaudRate.B[0];
    gLineCodingBuf[1] = m_pUsbCom->LineCoding.BaudRate.B[1];
    gLineCodingBuf[2] = m_pUsbCom->LineCoding.BaudRate.B[2];
    gLineCodingBuf[3] = m_pUsbCom->LineCoding.BaudRate.B[3];
    gLineCodingBuf[4] = m_pUsbCom->LineCoding.StopBit;
    gLineCodingBuf[5] = m_pUsbCom->LineCoding.Parity;
    gLineCodingBuf[6] = m_pUsbCom->LineCoding.DataBit;
   
}

void USBSerial_::SetControlLineState(uint8_t* sControlLineStateBuf)
{
    m_pUsbCom->LineState.ControlSignalBitmp.B[0] = sControlLineStateBuf[2];
    m_pUsbCom->LineState.ControlSignalBitmp.B[1] = sControlLineStateBuf[3];
    m_pUsbCom->LineState.Flag                    = SET;
}

void USBSerial_::SendBreak(uint8_t* SendBreakBuf)
{
    m_pUsbCom->SendBreak.DurationTime.B[0] = SendBreakBuf[2];
    m_pUsbCom->SendBreak.DurationTime.B[1] = SendBreakBuf[3];
    m_pUsbCom->SendBreak.Flag              = SET;
}



void USBSerial_::ReceiveDownstreamData()
{
    uint32_t   i;
    uint8_t         USB_DownstramBufTemp[COM_DATADOWNSTREAM_BUFFER_SIZE];
    
    m_pUsbCom->COM_USB_DataDownstream_Size = USB_GetEndpointRXData( m_DataDownStreamEP, &USB_DownstramBufTemp[0], DISABLE);
    
    if( m_pUsbCom->COM_USB_DataDownstream_Size !=0)
    {
        m_pUsbCom->COM_USB_DataDownstream_Busy = 1;
        for( i=0;  i< (m_pUsbCom->COM_USB_DataDownstream_Size);  i++ )
        {
            if( m_UsbRead_Cnt<SERIAL_BUFFER_SIZE )
            {
                m_UsbReadBuf[m_UsbRead_In] = USB_DownstramBufTemp[i];
                m_UsbRead_In = (m_UsbRead_In+1)%SERIAL_BUFFER_SIZE;
                m_UsbRead_Cnt++;
            }
            else 
            {
                m_UsbRead_Cnt = SERIAL_BUFFER_SIZE;
                
                m_UsbReadBuf[m_UsbRead_In]  = USB_DownstramBufTemp[i];
                m_UsbRead_In   = (m_UsbRead_In+1)%SERIAL_BUFFER_SIZE;
                m_UsbRead_Out  = (m_UsbRead_Out+1)%SERIAL_BUFFER_SIZE;
            }
        }
    }
    USB_SetEndpointStatus( m_DataDownStreamEP ,EP_RX_VALID);
}




 void USBSerial_::SetUARTState(void)
{
    if( m_pUsbCom->Status !=0)
    {
        if(m_pUsbCom->COM_USB_StatusUpstream_Busy==0)
        {
            m_pUsbCom->COM_Status_EP_SRAM[8] = m_pUsbCom->Status ;
            
            m_pUsbCom->COM_USB_StatusUpstream_Busy = 1;
            USB_SetEndpointTXData( m_StatusEP, &m_pUsbCom->COM_Status_EP_SRAM[0] , 10);
            
            m_pUsbCom->Status = 0;
        }
    }
    if( m_UsbComErrorCode == 0)
    {
        return;
    }


    //--------------------------------------------
    //D4 (bFraming)
    //    - A framing error has occurred.
    if( m_UsbComErrorCode & URT_IT_FE)
    {
        m_UsbComErrorCode = m_UsbComErrorCode & (~URT_IT_FE);
        m_pUsbCom->Status |= PSTN_URT_bFraming;    
        
        //To do......
    }
    //--------------------------------------------
    //D5 (bParity)
    //    - A parity error has occurred.
    if( m_UsbComErrorCode & URT_IT_PE)
    {
        m_UsbComErrorCode = m_UsbComErrorCode & (~URT_IT_PE);
        m_pUsbCom->Status |= PSTN_URT_bParity;    
        
        //To do......
    }
    //---------------------------------------------
    //D6 (bOverRun)
    //   - Received data has been discarded due to overrun in the device.
    if( m_pUsbCom->COM_USB_DataUpstream_OverrunFlag == 1 )
    {
        m_pUsbCom->COM_USB_DataUpstream_OverrunFlag = 0;
        m_pUsbCom->Status |= PSTN_URT_bOverRun;
        
        //To do......
    }
    if( m_UsbComErrorCode & URT_IT_ROVR)
    {
        m_UsbComErrorCode = m_UsbComErrorCode & (~URT_IT_ROVR);
        m_pUsbCom->Status |= PSTN_URT_bOverRun;
        
        //To do......
    }
    /*
    //---------------------------------------------
    //D7 (Reserved (future use)
    */
    // To do......
    
}



USBSerial_::USBSerial_( USB_EP_Struct*  pStatusEP,  
                        USB_EP_Struct*  pDataUpStreamEP, 
                        USB_EP_Struct*  pDataDownStreamEP   )
{
    m_Protocol = 1;
    
    m_StatusEP         = pStatusEP;
    m_DataUpStreamEP   = pDataUpStreamEP;
    m_DataDownStreamEP = pDataDownStreamEP;
    
    m_pUsbCom = &COM;

    m_pUsbCom->LineCoding.BaudRate.W        = 9600;
    m_pUsbCom->LineCoding.StopBit           = COM_STOPBIT_1_0;
    m_pUsbCom->LineCoding.Parity            = COM_PARITY_None;
    m_pUsbCom->LineCoding.DataBit           = 8;
    
    m_pUsbCom->COM_USB_DataDownstream_Busy      = 0;
    m_pUsbCom->COM_USB_DataUpstream_Busy        = 0;
    m_pUsbCom->COM_USB_StatusUpstream_Busy      = 0;
    m_pUsbCom->COM_USB_DataDownstream_Size      = 0;
    m_pUsbCom->COM_USB_DataUpstream_OverrunFlag = 0;
    m_pUsbCom->Status                           = 0;
    
    m_UsbComErrorCode = 0;
    
    m_available = 0;
    return;
}


void USBSerial_::DealUARTState(void)
{
    if( m_pUsbCom->Status !=0)
    {
        if(m_pUsbCom->COM_USB_StatusUpstream_Busy==0)
        {
            m_pUsbCom->COM_Status_EP_SRAM[8] = m_pUsbCom->Status ;
            
            m_pUsbCom->COM_USB_StatusUpstream_Busy = 1;
            USB_SetEndpointTXData( m_StatusEP, &m_pUsbCom->COM_Status_EP_SRAM[0] , 10);
            
            m_pUsbCom->Status = 0;
        }
    }
    if( m_UsbComErrorCode == 0)
    {
        return;
    }
    /*
    //-------------------------------------------
    //D0 (bRxCarrier) 
    //    - State of receiver carrier detection mechanism of device .
    //      This signal corresponds to V.24 signal 109 and RS-232 signal DCD.
    
    m_pUsbCom->Status |= PSTN_URT_bRxCarrier;
    
    //--------------------------------------------
    //D1 (bTxCarrier)
    //    - State of transmission carrier. 
    //      This signal corresponds to V.24 signal 106 and RS-232 signal DSR.
    m_pUsbCom->Status |= PSTN_URT_bTxCarrier;
    
    //--------------------------------------------
    //D2 (bBreak)
    //    - State of break detect mechanism of the device.
    m_pUsbCom->Status |= PSTN_URT_bBrek;
    
    //--------------------------------------------
    //D3 (bRingSignal)
    //    - State of ring signal detection of the device.
    m_pUsbCom->Status |= PSTN_URT_bRingSignal;
    
    */
    //--------------------------------------------
    //D4 (bFraming)
    //    - A framing error has occurred.
    if( m_UsbComErrorCode & URT_IT_FE)
    {
        m_UsbComErrorCode = m_UsbComErrorCode & (~URT_IT_FE);
        m_pUsbCom->Status |= PSTN_URT_bFraming;    
        
        //To do......
    }
    //--------------------------------------------
    //D5 (bParity)
    //    - A parity error has occurred.
    if( m_UsbComErrorCode & URT_IT_PE)
    {
        m_UsbComErrorCode = m_UsbComErrorCode & (~URT_IT_PE);
        m_pUsbCom->Status |= PSTN_URT_bParity;    
        
        //To do......
    }
    //---------------------------------------------
    //D6 (bOverRun)
    //   - Received data has been discarded due to overrun in the device.
    if( m_pUsbCom->COM_USB_DataUpstream_OverrunFlag == 1 )
    {
        m_pUsbCom->COM_USB_DataUpstream_OverrunFlag = 0;
        m_pUsbCom->Status |= PSTN_URT_bOverRun;
        
        //To do......
    }
    if( m_UsbComErrorCode & URT_IT_ROVR)
    {
        m_UsbComErrorCode = m_UsbComErrorCode & (~URT_IT_ROVR);
        m_pUsbCom->Status |= PSTN_URT_bOverRun;
        
        //To do......
    }
    /*
    //---------------------------------------------
    //D7 (Reserved (future use)
    */
    // To do......
    
}

void USBSerial_::Parameter_DeInit(void)
{
    m_UsbComErrorCode                    = 0;

    m_UsbRead_In = 0;
    m_UsbRead_Out = 0;
    m_UsbRead_Cnt = 0;
}


void USBSerial_::begin()
{
     begin(m_pUsbCom->LineCoding.BaudRate.W );
}


void USBSerial_::begin( unsigned long baudRate )
{
    __DRV_USB_DISCONNECT();
    delay(300);

    UsbSerial_SetAPIDefault();

    Parameter_DeInit();

    //==========================================================
    //1. COM Line Coding parameter intial
    //2. COM software control parameter inital.
    m_pUsbCom->LineCoding.BaudRate.W        = baudRate;
    m_pUsbCom->LineCoding.StopBit           = COM_STOPBIT_1_0;
    m_pUsbCom->LineCoding.Parity            = COM_PARITY_None;
    m_pUsbCom->LineCoding.DataBit           = 8;
    
    m_pUsbCom->COM_USB_DataDownstream_Busy      = 0;
    m_pUsbCom->COM_USB_DataUpstream_Busy        = 0;
    m_pUsbCom->COM_USB_StatusUpstream_Busy      = 0;
    m_pUsbCom->COM_USB_DataDownstream_Size      = 0;
    m_pUsbCom->COM_USB_DataUpstream_OverrunFlag = 0;
    m_pUsbCom->Status                           = 0;

    m_UsbComErrorCode                    = 0;

    //=========================================================
    m_pUsbCom->COM_Status_EP_SRAM[0] = 0xA1;                              
    m_pUsbCom->COM_Status_EP_SRAM[1] = PSTN_SERIAL_STATE;                 
    m_pUsbCom->COM_Status_EP_SRAM[2] = 0x00;                              
    m_pUsbCom->COM_Status_EP_SRAM[3] = 0x00;                              
    m_pUsbCom->COM_Status_EP_SRAM[4] = 0x00;
    m_pUsbCom->COM_Status_EP_SRAM[5] = 0x00;
    m_pUsbCom->COM_Status_EP_SRAM[6] = 0x02;
    m_pUsbCom->COM_Status_EP_SRAM[7] = 0x00;
    m_pUsbCom->COM_Status_EP_SRAM[8] = m_pUsbCom->Status ;
    m_pUsbCom->COM_Status_EP_SRAM[9] = 0x00;  

    //---------------------------------------
    //USB Power Control Relationship
    UnProtectModuleReg(PWprotect);

    PW_PeriphSLEEPModeContinuous_Config(PW_SLPPO_USB,ENABLE);

    PW_PeriphSTOPModeWakeUp_Config( PW_WKSTP_USB , ENABLE);

    ProtectModuleReg(PWprotect);

    __DRV_USB_CONNECT();
    //---------------------------------------

    //USB Inital
    API_USBD_Inital();

    NVIC_SetPriority(USB_IRQn,  1);

    m_available = 1;
    return;
}


void USBSerial_::end(void)
{
    Parameter_DeInit();
    __DRV_USB_DISCONNECT();
    USB_SetAPIDefault();

    m_available = 0;
    return;
}


int USBSerial_::available(void)
{
    return (m_available != 0);
}



int USBSerial_::availableForWrite(void)
{
    return available();
}



int USBSerial_::peek(void)
{
    int32_t data = -1;
    
    if( !available() )
    {
        return -1;
    }
    
    if( m_UsbRead_Cnt > 0)
    {
        data = m_UsbReadBuf[ m_UsbRead_Out ];
    }
    return data;
}


int USBSerial_::read(void)
{
    int32_t data = -1;

    if( !available() )
    {
        return -1;
    }

    if( m_UsbRead_Cnt > 0)
    {
        data = m_UsbReadBuf[ m_UsbRead_Out ];
        m_UsbRead_Out++;
        m_UsbRead_Out = (m_UsbRead_Out % SERIAL_BUFFER_SIZE);
        m_UsbRead_Cnt--;
        return (0x000000FF & data);
    }
    else
    {
        m_UsbRead_In = m_UsbRead_Out;
        m_UsbRead_Cnt = 0;
        return -1;
    }

    return (0x000000FF & data);

}


void USBSerial_::flush(void)
{
    m_UsbRead_In = 0;
    m_UsbRead_Out = 0;
    m_UsbRead_Cnt = 0;
    return;
}


#define USBSerial_OUTTIME_CNT      300000
#if 0

size_t USBSerial_::write(const uint8_t *buffer, size_t size)
{

    volatile uint32_t  OuttimeCnt = 0;
    volatile uint8_t  flag;
    int32_t USBD_COM_mainTmp ;

    int32_t i,j;


    //==========================================================
    // The USB device has not enumeration success yet.
    if(  !API_UsbSerial_IsEmulationOK() )
    {
        return 0;
    }
    
    //==========================================================
    //--------------------------------------------------------------
    //Set URT RX Data to USB Host.
    
    flag = m_pUsbCom->COM_USB_DataUpstream_Busy;
    OuttimeCnt = 0;
    while(  flag == 1 )
    {
        flag = m_pUsbCom->COM_USB_DataUpstream_Busy;

        //NVIC_SetPriority(USB_IRQn,  1);
        //NVIC_EnableIRQ(USB_IRQn);

        OuttimeCnt++;
        if( OuttimeCnt > USBSerial_OUTTIME_CNT )
        {
            return 0;
        }
    }
    
    flag = m_pUsbCom->COM_USB_DataUpstream_Busy;
    if( flag == 0)
    {
        USBD_COM_mainTmp   = 0;
        
        for(j=size;  j>=COM_DATAUPSTREAM_BUFFER_SIZE;  j=(j-COM_DATAUPSTREAM_BUFFER_SIZE) )
        {
            flag = m_pUsbCom->COM_USB_DataUpstream_Busy;
            OuttimeCnt = 0;
            while(  flag == 1 )
            {
                flag = m_pUsbCom->COM_USB_DataUpstream_Busy;
                //NVIC_SetPriority(USB_IRQn,  1);
                //NVIC_EnableIRQ(USB_IRQn);
                OuttimeCnt++;
                if( OuttimeCnt > USBSerial_OUTTIME_CNT )
                {
                    return USBD_COM_mainTmp;
                }
            }

            for( i=0; i<COM_DATAUPSTREAM_BUFFER_SIZE; i++ )
            {
                m_UsbWriteBuf[i] = buffer[USBD_COM_mainTmp];
                USBD_COM_mainTmp    = USBD_COM_mainTmp   + 1;
            }

            m_pUsbCom->COM_USB_DataUpstream_Busy = 1;
            USB_SetEndpointTXData( m_DataUpStreamEP,   &m_UsbWriteBuf[0] , COM_DATAUPSTREAM_BUFFER_SIZE);
        }

        if( j>0 )
        {
            flag = m_pUsbCom->COM_USB_DataUpstream_Busy;
            OuttimeCnt = 0;
            while(  flag == 1 )
            {
                flag = m_pUsbCom->COM_USB_DataUpstream_Busy;
                //NVIC_SetPriority(USB_IRQn,  1);
                //NVIC_EnableIRQ(USB_IRQn);
                OuttimeCnt++;
                if( OuttimeCnt > USBSerial_OUTTIME_CNT )
                {
                    return USBD_COM_mainTmp;
                }
            }
            for( i=0; i<j; i++ )
            {
                m_UsbWriteBuf[i] = buffer[USBD_COM_mainTmp];
                USBD_COM_mainTmp    = USBD_COM_mainTmp   + 1;
            }

            m_pUsbCom->COM_USB_DataUpstream_Busy = 1;
            USB_SetEndpointTXData( m_DataUpStreamEP,   &m_UsbWriteBuf[0] , j );

/*
            flag = m_pUsbCom->COM_USB_DataUpstream_Busy;
            OuttimeCnt = 0;
            while(  flag == 1 )
            {
                flag = m_pUsbCom->COM_USB_DataUpstream_Busy;
                //NVIC_SetPriority(USB_IRQn,  1);
                //NVIC_EnableIRQ(USB_IRQn);

                OuttimeCnt++;
                if( OuttimeCnt > USBSerial_OUTTIME_CNT )
                {
                    return size;
                }
            }
*/

        }
    }

    //SetUARTState();
    //===========================================================
    if( m_pUsbCom->LineState.Flag == 1)
    {
        // To do......
        m_pUsbCom->LineState.Flag = 0;
    }        
    if( m_pUsbCom->SendBreak.Flag == 1)
    {
        // To do......
        m_pUsbCom->SendBreak.Flag = 0;
    }

    return size;
}
#endif

size_t USBSerial_::write(const uint8_t *buffer, size_t size)
{
    do
    {
        if( size > COM_DATAUPSTREAM_BUFFER_SIZE )
        {
            writex( buffer, COM_DATAUPSTREAM_BUFFER_SIZE );
            buffer = buffer+ COM_DATAUPSTREAM_BUFFER_SIZE;
            size = size - COM_DATAUPSTREAM_BUFFER_SIZE;
            delay(10);
        }
        else 
        {
            writex( buffer, size );
            buffer = buffer+ size;
            size = 0;
        }
    }while( size>0 );
    
    return size;
}

#if 1
size_t USBSerial_::writex(const uint8_t *buffer, size_t size)
{
    volatile uint32_t  OuttimeCnt = 0;
    volatile uint8_t  flag;
    int32_t USBD_COM_mainTmp ;

    size_t i;

    //==========================================================
    // The USB device has not enumeration success yet.
    if(  !API_UsbSerial_IsEmulationOK() )
    {
        return 0;
    }
    
    //==========================================================
    //--------------------------------------------------------------
    //Set URT RX Data to USB Host.
    flag = m_pUsbCom->COM_USB_DataUpstream_Busy;
    OuttimeCnt = 0;
    while(  flag == 1 )
    {
        flag = m_pUsbCom->COM_USB_DataUpstream_Busy;

        //NVIC_SetPriority(USB_IRQn,  1);
        //NVIC_EnableIRQ(USB_IRQn);

        OuttimeCnt++;
        if( OuttimeCnt > USBSerial_OUTTIME_CNT )
        {
            return 0;
        }
    }
    if( size > COM_DATAUPSTREAM_BUFFER_SIZE )
    {
        size = COM_DATAUPSTREAM_BUFFER_SIZE;
    }

    
    flag = m_pUsbCom->COM_USB_DataUpstream_Busy;
    if( flag == 0)
    {
        USBD_COM_mainTmp   = 0;
        
        for( i=0; i<size; i++ )
        {
            m_UsbWriteBuf[i] = buffer[USBD_COM_mainTmp];
            USBD_COM_mainTmp    = USBD_COM_mainTmp   + 1;
        }

        m_pUsbCom->COM_USB_DataUpstream_Busy = 1;
        USB_SetEndpointTXData( m_DataUpStreamEP,   &m_UsbWriteBuf[0] , size);
    }

    //SetUARTState();
    //===========================================================
    if( m_pUsbCom->LineState.Flag == 1)
    {
        // To do......
        m_pUsbCom->LineState.Flag = 0;
    }        
    if( m_pUsbCom->SendBreak.Flag == 1)
    {
        // To do......
        m_pUsbCom->SendBreak.Flag = 0;
    }

    return size;
}
#endif


size_t USBSerial_::write(uint8_t data)
{
    volatile uint32_t  OuttimeCnt = 0;
    volatile uint8_t  flag;

    //==========================================================
    // The USB device has not enumeration success yet.
    if(  !API_UsbSerial_IsEmulationOK() )
    {
        return 0;
    }

    flag = m_pUsbCom->COM_USB_DataUpstream_Busy;
    OuttimeCnt = 0;
    while(  flag == 1 )
    {
        flag = m_pUsbCom->COM_USB_DataUpstream_Busy;
        //NVIC_SetPriority(USB_IRQn,  1);
        //NVIC_EnableIRQ(USB_IRQn);
        OuttimeCnt++;
        if( OuttimeCnt > USBSerial_OUTTIME_CNT )
        {
            return 0;
        }
    }

    //==========================================================
    //--------------------------------------------------------------
    //Set URT RX Data to USB Host.
    if( m_pUsbCom->COM_USB_DataUpstream_Busy == 0)
    {
        m_pUsbCom->COM_USB_DataUpstream_Busy = 1;
        m_UsbWriteBuf[0] = data;
        USB_SetEndpointTXData( m_DataUpStreamEP,   &m_UsbWriteBuf[0] , 1);
    }
    
    //===========================================================
    if( m_pUsbCom->LineState.Flag == 1)
    {
        // To do......
        m_pUsbCom->LineState.Flag = 0;
    }        
    if( m_pUsbCom->SendBreak.Flag == 1)
    {
        // To do......
        m_pUsbCom->SendBreak.Flag = 0;
    }

    return 1;
}






int USBSerial_::printHex(  uint8_t uc_data   )
{
    int i;
    
    uint8_t u8_data;
    
    for( i=2; i>0; i-- )
    {
        u8_data = ( (uc_data >> ((i-1)*4)) & 0x0F);
        if( u8_data>9 )
        {
            write( ('a'+ u8_data -10) );
        }
        else
        {
            write( ('0'+ u8_data) );
        }
    }

    return 0;
}
int USBSerial_::printHex(  uint16_t uc_data   )
{
    int i;
    
    uint8_t u8_data;
    
    for( i=4; i>0; i-- )
    {
        u8_data = ( (uc_data >> ((i-1)*4)) & 0x000F);
        if( u8_data>9 )
        {
            write( ('a'+ u8_data -10) );
        }
        else
        {
            write( ('0'+ u8_data) );
        }
    }

    return 0;
}

int USBSerial_::printHex(  uint32_t uc_data   )
{
    int i;
    
    uint8_t u8_data;
    
    for( i=8; i>0; i-- )
    {
        u8_data = ( (uc_data >> ((i-1)*4)) & 0x0000000F);
        if( u8_data>9 )
        {
            write( ('a'+ u8_data -10) );
        }
        else
        {
            write( ('0'+ u8_data) );
        }
    }

    return 0;
}

int USBSerial_::printDec(  uint32_t uc_data   )
{
    int i;
    uint32_t dev = 1; 
    uint32_t writeData = 0; 
    
    for( i=0; (i<16); i++ )
    {
        dev = dev*10;
        if(  (uc_data/dev) == 0  )
        {
            break;
        }
    }
    
    for( i=0; (i<16); i++ )
    {
        dev = dev/10;
        if( dev > 0 )
        {
            writeData = uc_data/dev;
            write( ('0'+ writeData) );

            uc_data   =  uc_data%dev;
        } 
        else
        {
            break;
        }
    }

    return 0;
}

   

#if 0
void USBSerial_::SetUARTState(void)
{
    if( m_pUsbCom->Status !=0)
    {
        if(m_pUsbCom->COM_USB_StatusUpstream_Busy==0)
        {
            m_pUsbCom->COM_Status_EP_SRAM[8] = m_pUsbCom->Status ;
            
            m_pUsbCom->COM_USB_StatusUpstream_Busy = 1;
            USB_SetEndpointTXData( m_StatusEP, &m_pUsbCom->COM_Status_EP_SRAM[0] , 10);
            
            COM.Status = 0;
        }
    }

    if( m_UsbComErrorCode == 0)
    {
        return;
    }

    /*
    //-------------------------------------------
    //D0 (bRxCarrier) 
    //    - State of receiver carrier detection mechanism of device .
    //      This signal corresponds to V.24 signal 109 and RS-232 signal DCD.
    
    COM.Status |= PSTN_URT_bRxCarrier;
    
    //--------------------------------------------
    //D1 (bTxCarrier)
    //    - State of transmission carrier. 
    //      This signal corresponds to V.24 signal 106 and RS-232 signal DSR.
    COM.Status |= PSTN_URT_bTxCarrier;
    
    //--------------------------------------------
    //D2 (bBreak)
    //    - State of break detect mechanism of the device.
    COM.Status |= PSTN_URT_bBrek;
    
    //--------------------------------------------
    //D3 (bRingSignal)
    //    - State of ring signal detection of the device.
    COM.Status |= PSTN_URT_bRingSignal;
    
    */
    //--------------------------------------------
    //D4 (bFraming)
    //    - A framing error has occurred.
    if( m_UsbComErrorCode & URT_IT_FE)
    {
        m_UsbComErrorCode = m_UsbComErrorCode & (~URT_IT_FE);
        m_pUsbCom->Status |= PSTN_URT_bFraming;    
        
        //To do......
    }

    //--------------------------------------------
    //D5 (bParity)
    //    - A parity error has occurred.
    if( m_UsbComErrorCode & URT_IT_PE)
    {
        m_UsbComErrorCode = m_UsbComErrorCode & (~URT_IT_PE);
        m_pUsbCom->Status |= PSTN_URT_bParity;    
        
        //To do......
    }

    //---------------------------------------------
    //D6 (bOverRun)
    //   - Received data has been discarded due to overrun in the device.
    if( m_pUsbCom->COM_USB_DataUpstream_OverrunFlag == 1 )
    {
        m_pUsbCom->COM_USB_DataUpstream_OverrunFlag = 0;
        m_pUsbCom->Status |= PSTN_URT_bOverRun;
        
        //To do......
    }
    if( m_UsbComErrorCode & URT_IT_ROVR)
    {
        m_UsbComErrorCode = m_UsbComErrorCode & (~URT_IT_ROVR);
        m_pUsbCom->Status |= PSTN_URT_bOverRun;
        
        //To do......
    }
    /*
    //---------------------------------------------
    //D7 (Reserved (future use)
    */
    // To do......
}

#endif




USBSerial_   USBSerial(COM_STATUS_EP,  COM_DATAUPSTREAM_EP,  COM_DATADOWNSTREAM_EP );











#endif




///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////


