Simple USBHost library for STM32F746NG Discovery board. Only either the Fastspeed or the Highspeed port can be used( not both together)

Dependents:   DISCO-F746NG_USB_Host

Fork of KL46Z-USBHost by Norimasa Okamoto

USBHost/TARGET_STM32F7/USBHALHost_F746NG.cpp

Committer:
DieterGraef
Date:
2016-06-13
Revision:
24:5396b6a93262
Child:
25:7d6d9fc471bf

File content as of revision 24:5396b6a93262:

#if defined(TARGET_DISCO_F746NG)
#include "mbed.h"
#include "stm32f7xx_hal.h"
#include "USBHALHost.h"
#include <algorithm>
#include "USB_Helper.h"
#ifdef _USB_DBG
//extern RawSerial pc;
//RawSerial pc(USBTX,USBRX);
#include "mydebug.h"
#define USB_DBG(...) do{printf("[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);printf(__VA_ARGS__);printf("\n");} while(0);
#define USB_DBG_HEX(A,B) debug_hex<RawSerial>(pc,A,B)

#else
#define USB_DBG(...) while(0)
#define USB_DBG_HEX(A,B) while(0)
#endif

#undef USB_TEST_ASSERT
void usb_test_assert_internal(const char *expr, const char *file, int line);
#define USB_TEST_ASSERT(EXPR) while(!(EXPR)){usb_test_assert_internal(#EXPR,__FILE__,__LINE__);}

#define USB_TRACE1(A) while(0)

#define USB_INFO(...) do{fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");}while(0);

__IO bool attach_done = false;

void delay_ms(uint32_t t)
{
    wait_ms(t);
}

// usbh_conf.c

//__attribute__((section(".dmatransfer")));


void HAL_HCD_MspInit(HCD_HandleTypeDef* hhcd)
{
    GPIO_InitTypeDef  GPIO_InitStruct;
    if(hhcd->Instance==USB_OTG_FS)
    {
        /* Configure USB FS GPIOs */
        __HAL_RCC_GPIOA_CLK_ENABLE();
        __HAL_RCC_GPIOD_CLK_ENABLE();
        GPIO_InitStruct.Pin = (GPIO_PIN_11 | GPIO_PIN_12);
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS;
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

        GPIO_InitStruct.Pin = GPIO_PIN_10;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
        GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS;
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

        /* Configure POWER_SWITCH IO pin */
        GPIO_InitStruct.Pin = GPIO_PIN_5;
        GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

        /* Enable USB FS Clocks */
        __HAL_RCC_USB_OTG_FS_CLK_ENABLE();
    }
    if(hhcd->Instance==USB_OTG_HS)
    {
        /* Peripheral clock enable */
        __HAL_RCC_GPIOA_CLK_ENABLE();
        __HAL_RCC_GPIOB_CLK_ENABLE();
        __HAL_RCC_GPIOC_CLK_ENABLE();
        __HAL_RCC_GPIOH_CLK_ENABLE();
        /* CLK */
        GPIO_InitStruct.Pin = GPIO_PIN_5;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS;
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

        /* D0 */
        GPIO_InitStruct.Pin = GPIO_PIN_3;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS;
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

        /* D1 D2 D3 D4 D5 D6 D7 */
        GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_5 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS;
        HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

        /* STP */
        GPIO_InitStruct.Pin = GPIO_PIN_0;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS;
        HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

        /* NXT */
        GPIO_InitStruct.Pin = GPIO_PIN_4;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS;
        HAL_GPIO_Init(GPIOH, &GPIO_InitStruct);

        /* DIR */
        GPIO_InitStruct.Pin = GPIO_PIN_2;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS;
        HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

        __HAL_RCC_USB_OTG_HS_ULPI_CLK_ENABLE();

        /* Enable USB HS Clocks */
        __HAL_RCC_USB_OTG_HS_CLK_ENABLE();
    }
}

// stm32f4xx_it.c
extern "C" {
    void HAL_HCD_Connect_Callback(HCD_HandleTypeDef *hhcd)
    {
        //USB_TRACE1(hhcd);
        attach_done = true;
    }

} // extern "C"

USBHALHost* USBHALHost::instHost;

USBHALHost::USBHALHost(int InterfaceNumber)
{
    IF_N=InterfaceNumber;
    hhcd=&hhcd_USB;
    instHost = this;
}

void USBHALHost::init()
{
    if(IF_N==USB_FastSpeed)
    {
        hhcd_USB.Instance = USB_OTG_FS;
        hhcd_USB.Init.Host_channels = 11;
        hhcd_USB.Init.dma_enable = 0;
        hhcd_USB.Init.low_power_enable = 0;
        hhcd_USB.Init.phy_itface = HCD_PHY_EMBEDDED;
        hhcd_USB.Init.Sof_enable = 1;
        hhcd_USB.Init.speed = HCD_SPEED_FULL;
        hhcd_USB.Init.vbus_sensing_enable = 0;
        hhcd_USB.Init.lpm_enable = 0;

        HAL_HCD_Init(&hhcd_USB);
        /* Peripheral interrupt init*/
        /* Sets the priority grouping field */
        NVIC_SetVector(OTG_FS_IRQn, (uint32_t)&_usbisr);
        HAL_NVIC_SetPriority(OTG_FS_IRQn,  6, 0);
        HAL_NVIC_EnableIRQ(OTG_FS_IRQn);

        HAL_HCD_Start(&hhcd_USB);

        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_5, GPIO_PIN_RESET);

        bool lowSpeed = wait_attach();
        delay_ms(200);
        HAL_HCD_ResetPort(&hhcd_USB);
        delay_ms(100); // Wait for 100 ms after Reset
        addDevice(NULL, 0, lowSpeed);
    }
    if(IF_N==USB_HighSpeed)
    {
        hhcd_USB.Instance = USB_OTG_HS;
        hhcd_USB.Init.Host_channels = 8;
        hhcd_USB.Init.dma_enable = 1;
        hhcd_USB.Init.low_power_enable = 0;
        hhcd_USB.Init.phy_itface = HCD_PHY_ULPI;
        hhcd_USB.Init.Sof_enable = 1;
        hhcd_USB.Init.speed = HCD_SPEED_HIGH;
        hhcd_USB.Init.vbus_sensing_enable = 0;
        hhcd_USB.Init.use_external_vbus = 1;
        hhcd_USB.Init.lpm_enable = 0;

        HAL_HCD_Init(&hhcd_USB);
        NVIC_SetVector(OTG_HS_IRQn, (uint32_t)&_usbisr);
        HAL_NVIC_SetPriority(OTG_HS_IRQn,  6, 0);
        HAL_NVIC_EnableIRQ(OTG_HS_IRQn);

        HAL_HCD_Start(&hhcd_USB);

        bool lowSpeed = wait_attach();
        delay_ms(200);
        HAL_HCD_ResetPort(&hhcd_USB);
        delay_ms(100); // Wait for 100 ms after Reset
        addDevice(NULL, 0, lowSpeed);
    }
}

bool USBHALHost::wait_attach()
{
    Timer t;
    t.reset();
    t.start();
    while(!attach_done)
    {
        if (t.read_ms() > 5*1000)
        {
            t.reset();
            USB_INFO("Please attach USB device.");
        }
    }
    wait_ms(100);
    return HAL_HCD_GetCurrentSpeed(&hhcd_USB) == USB_OTG_SPEED_LOW;
}



int USBHALHost::token_setup(USBEndpoint* ep, SETUP_PACKET* setup, uint16_t wLength)
{
    const uint8_t ep_addr = 0x00;
    HC hc(&hhcd_USB);
    HCD_URBStateTypeDef st;
    USBDeviceConnected* dev = ep->getDevice();
    if(IF_N==USB_FastSpeed)
    {
        hc.Init(IF_N, ep_addr,
                dev->getAddress(),
                dev->getSpeed() ? HCD_SPEED_LOW : HCD_SPEED_FULL,
                EP_TYPE_CTRL, ep->getSize());
    }
    else
    {
        hc.Init(IF_N,ep_addr,
                dev->getAddress(),
                dev->getSpeed() ? HCD_SPEED_LOW : HCD_SPEED_HIGH ,
                EP_TYPE_CTRL, ep->getSize());
    }

    setup->wLength = wLength;
    st=hc.GetURBState();
    hc.SubmitRequest(IF_N,(uint8_t*)setup, 8, true); // PID_SETUP
    while(hc.GetURBState() == URB_IDLE);

    switch(hc.GetURBState())
    {
    case URB_DONE:
        LastStatus = ACK;
        break;
    default:
        LastStatus = 0xff;
        break;
    }
    ep->setData01(DATA1);
    return 8;
}

int USBHALHost::token_in(USBEndpoint* ep, uint8_t* data, int size, int retryLimit)
{
    SCB_InvalidateDCache_by_Addr((uint32_t *)data,size);
    switch(ep->getType())
    {
    case CONTROL_ENDPOINT:
        return token_ctl_in(ep, data, size, retryLimit);
    case INTERRUPT_ENDPOINT:
        return token_int_in(ep, data, size);
    case BULK_ENDPOINT:
        return token_blk_in(ep, data, size, retryLimit);
    }
    return -1;
}

int USBHALHost::token_ctl_in(USBEndpoint* ep, uint8_t* data, int size, int retryLimit)
{
    const uint8_t ep_addr = 0x80;
    HC hc(&hhcd_USB);
    HCD_URBStateTypeDef st;
    USBDeviceConnected* dev = ep->getDevice();
    if(IF_N==USB_FastSpeed)
    {
        hc.Init(IF_N,ep_addr,
                dev->getAddress(),
                dev->getSpeed() ? HCD_SPEED_LOW : HCD_SPEED_FULL,
                EP_TYPE_CTRL, ep->getSize());
    }
    else
    {
        hc.Init(IF_N,ep_addr,
                dev->getAddress(),
                dev->getSpeed() ? HCD_SPEED_LOW : HCD_SPEED_HIGH ,
                EP_TYPE_CTRL, ep->getSize());
    }

    hc.SetToggle((ep->getData01() == DATA0) ? 0 : 1);
    st=hc.GetURBState();
    SCB_InvalidateDCache_by_Addr((uint32_t *)data,size);
    wait_ms(1);
    hc.SubmitRequest(IF_N,data, size);
    while(hc.GetURBState() == URB_IDLE);
    CPU_CACHE_Flush((uint32_t *)data,size);
    st=hc.GetURBState();
    switch(hc.GetURBState())
    {
    case URB_DONE:
        LastStatus = ACK;
        break;
    default:
        LastStatus = 0xff;
        return -1;
    }
    ep->toggleData01();
    return hc.GetXferCount();
}

int USBHALHost::token_int_in(USBEndpoint* ep, uint8_t* data, int size)
{
    HC hc(&hhcd_USB);
    HCD_URBStateTypeDef st;
    USBDeviceConnected* dev = ep->getDevice();
    if(IF_N==USB_FastSpeed)
    {
        hc.Init(IF_N,ep->getAddress(),
                dev->getAddress(),
                dev->getSpeed() ? HCD_SPEED_LOW : HCD_SPEED_FULL,
                EP_TYPE_INTR, ep->getSize());
    }
    else
    {
        hc.Init(IF_N,ep->getAddress(),
                dev->getAddress(),
                dev->getSpeed() ? HCD_SPEED_LOW : HCD_SPEED_HIGH ,
                EP_TYPE_INTR, ep->getSize());
    }

    hc.SetToggle((ep->getData01() == DATA0) ? 0 : 1);
    st=hc.GetURBState();
    SCB_InvalidateDCache_by_Addr((uint32_t *)data,size);
    hc.SubmitRequest(IF_N,data, size);
    while(hc.GetURBState() == URB_IDLE);
    CPU_CACHE_Flush((uint32_t *)data,size);
    switch(hc.GetURBState())
    {
    case URB_DONE:
        switch(hc.GetState())
        {
        case HC_XFRC:
            LastStatus = ep->getData01();
            ep->toggleData01();
            return hc.GetXferCount();
        case HC_NAK:
            LastStatus = NAK;
            return -1;
        }
        break;
    }
    LastStatus = STALL;
    return -1;
}

int USBHALHost::token_blk_in(USBEndpoint* ep, uint8_t* data, int size, int retryLimit)
{
    HC hc(&hhcd_USB);
    HCD_URBStateTypeDef st;
    USBDeviceConnected* dev = ep->getDevice();
    if(IF_N==USB_FastSpeed)
    {
        hc.Init(IF_N,
            ep->getAddress(),
            dev->getAddress(),
            HCD_SPEED_FULL,
            EP_TYPE_BULK, ep->getSize());
    }
    else
    {
        hc.Init(IF_N,
            ep->getAddress(),
            dev->getAddress(),
            HCD_SPEED_HIGH,
            EP_TYPE_BULK, ep->getSize());
    }

    hc.SetToggle((ep->getData01() == DATA0) ? 0 : 1);

    int retry = 0;
    do
    {
        st=hc.GetURBState();
        SCB_InvalidateDCache_by_Addr((uint32_t *)data,size);
        hc.SubmitRequest(IF_N,data, size);
        while(hc.GetURBState() == URB_IDLE);
        CPU_CACHE_Flush((uint32_t *)data,size);
        st=hc.GetURBState();
        switch(st)
        {
        case URB_DONE:
            switch(hc.GetState())
            {
            case HC_XFRC:
                LastStatus = ep->getData01();
                ep->toggleData01();
                return hc.GetXferCount();
            case HC_NAK:
                LastStatus = NAK;
                if (retryLimit > 0)
                {
                    delay_ms(1 + 10 * retry);
                }
                break;
            default:
                break;
            }
            break;
        case URB_STALL:
            LastStatus = STALL;
            return -1;
        default:
            LastStatus = STALL;
            delay_ms(500 + 100 * retry);
            break;
        }
    }
    while(retry++ < retryLimit);
    return -1;
}

int USBHALHost::token_out(USBEndpoint* ep, const uint8_t* data, int size, int retryLimit)
{
    CPU_CACHE_Flush((uint32_t *)data,size);
    SCB_InvalidateDCache_by_Addr((uint32_t *)data,size);
    switch(ep->getType())
    {
    case CONTROL_ENDPOINT:
        return token_ctl_out(ep, data, size, retryLimit);
    case INTERRUPT_ENDPOINT:
        return token_int_out(ep, data, size);
    case BULK_ENDPOINT:
        return token_blk_out(ep, data, size, retryLimit);
    }
    return -1;
}

int USBHALHost::token_ctl_out(USBEndpoint* ep, const uint8_t* data, int size, int retryLimit)
{
    const uint8_t ep_addr = 0x00;
    HC hc(&hhcd_USB);
    HCD_URBStateTypeDef st;
    USBDeviceConnected* dev = ep->getDevice();
    if(IF_N==USB_FastSpeed)
    {
        hc.Init(IF_N,ep_addr,
                dev->getAddress(),
                dev->getSpeed() ? HCD_SPEED_LOW : HCD_SPEED_FULL,
                EP_TYPE_CTRL, ep->getSize());
    }
    else
    {
        hc.Init(IF_N,ep_addr,
                dev->getAddress(),
                dev->getSpeed() ? HCD_SPEED_LOW : HCD_SPEED_HIGH ,
                EP_TYPE_CTRL, ep->getSize());
    }

    hc.SetToggle((ep->getData01() == DATA0) ? 0 : 1);

    do
    {
        st=hc.GetURBState();
        CPU_CACHE_Flush((uint32_t *)data,size);
        wait_ms(1);
        hc.SubmitRequest(IF_N,(uint8_t*)data, size);
        while(hc.GetURBState() == URB_IDLE);
        SCB_InvalidateDCache_by_Addr((uint32_t *)data,size);
        switch(hc.GetURBState())
        {
        case URB_DONE:
            LastStatus = ACK;
            ep->toggleData01();
            return size;

        default:
            break;
        }
        delay_ms(1);
    }
    while(retryLimit-- > 0);
    return -1;
}

int USBHALHost::token_int_out(USBEndpoint* ep, const uint8_t* data, int size)
{
    HC hc(&hhcd_USB);
    HCD_URBStateTypeDef st;
    USBDeviceConnected* dev = ep->getDevice();
    if(IF_N==USB_FastSpeed)
    {
        hc.Init(IF_N,
            ep->getAddress(),
            dev->getAddress(),
            dev->getSpeed() ? HCD_SPEED_LOW : HCD_SPEED_FULL,
            EP_TYPE_INTR, ep->getSize());
    }
    else
    {
        hc.Init(IF_N,
            ep->getAddress(),
            dev->getAddress(),
            dev->getSpeed() ? HCD_SPEED_LOW : HCD_SPEED_HIGH ,
            EP_TYPE_INTR, ep->getSize());
    }

    hc.SetToggle((ep->getData01() == DATA0) ? 0 : 1);
    st=hc.GetURBState();
    CPU_CACHE_Flush((uint32_t *)data,size);
    hc.SubmitRequest(IF_N,(uint8_t*)data, size);
    while(hc.GetURBState() == URB_IDLE);
    SCB_InvalidateDCache_by_Addr((uint32_t *)data,size);
    if (hc.GetURBState() != URB_DONE)
    {
        return -1;
    }
    ep->toggleData01();
    return size;
}

int USBHALHost::token_blk_out(USBEndpoint* ep, const uint8_t* data, int size, int retryLimit)
{
    HC hc(&hhcd_USB);
    HCD_URBStateTypeDef st;
    USBDeviceConnected* dev = ep->getDevice();
    if(IF_N==USB_FastSpeed)
    {


        hc.Init(IF_N,
            ep->getAddress(), dev->getAddress(),
            HCD_SPEED_FULL, EP_TYPE_BULK, ep->getSize());
    }
    else
    {
        hc.Init(IF_N,
            ep->getAddress(), dev->getAddress(),
            HCD_SPEED_HIGH, EP_TYPE_BULK, ep->getSize());
    }
    hc.SetToggle((ep->getData01() == DATA0) ? 0 : 1);

    int retry = 0;
    do
    {
        st=hc.GetURBState();
        CPU_CACHE_Flush((uint32_t *)data,size);
        hc.SubmitRequest(IF_N,(uint8_t*)data, size);
        while(hc.GetURBState() == URB_IDLE);
        SCB_InvalidateDCache_by_Addr((uint32_t *)data,size);
        switch(hc.GetURBState())
        {
        case URB_DONE:
            switch(hc.GetState())
            {
            case HC_XFRC: // ACK
                LastStatus = ep->getData01();
                ep->toggleData01();
                return size;
            default:
                break;
            }
            break;
        case URB_NOTREADY: // HC_NAK
            LastStatus = NAK;
            delay_ms(100 * retry);
            break;
        default:
            LastStatus = STALL;
            return -1;
        }
    }
    while(retry++ < retryLimit);
    return -1;
}

int USBHALHost::token_iso_in(USBEndpoint* ep, uint8_t* data, int size)
{
    HCD_URBStateTypeDef st;
    HC* hc = ep->getHALData<HC*>();
    if (hc == NULL)
    {
        hc = new HC(&hhcd_USB);
        ep->setHALData<HC*>(hc);
        USBDeviceConnected* dev = ep->getDevice();
        if(IF_N==USB_FastSpeed)
        {


            hc->Init(IF_N,
                ep->getAddress(), dev->getAddress(),
                HCD_SPEED_FULL, EP_TYPE_ISOC, ep->getSize());
        }
        else
        {
            hc->Init(IF_N,
                ep->getAddress(), dev->getAddress(),
                HCD_SPEED_HIGH, EP_TYPE_ISOC, ep->getSize());
        }
    }
    st=hc->GetURBState();
    SCB_InvalidateDCache_by_Addr((uint32_t *)data,size);
    hc->SubmitRequest(IF_N,data, size);
    while(hc->GetURBState() == URB_IDLE);
    CPU_CACHE_Flush((uint32_t *)data,size);
    return hc->GetXferCount();
}

int USBHALHost::multi_token_in(USBEndpoint* ep, uint8_t* data, size_t total, bool block)
{
    if (total == 0)
    {
        return token_in(ep);
    }
    int retryLimit = block ? 10 : 0;
    int read_len = 0;
    for(int n = 0; read_len < total; n++)
    {
        int size = std::min((int)total-read_len, ep->getSize());
        int result = token_in(ep, data+read_len, size, retryLimit);
        if (result < 0)
        {
            if (block)
            {
                return -1;
            }
            if (LastStatus == NAK)
            {
                if (n == 0)
                {
                    return -1;
                }
                break;
            }
            return result;
        }
        read_len += result;
        if (result < ep->getSize())
        {
            break;
        }
    }
    return read_len;
}

int USBHALHost::multi_token_out(USBEndpoint* ep, const uint8_t* data, size_t total)
{
    if (total == 0)
    {
        return token_out(ep);
    }
    int write_len = 0;
    for(int n = 0; write_len < total; n++)
    {
        int size = std::min((int)total-write_len, ep->getSize());
        int result = token_out(ep, data+write_len, size);
        if (result < 0)
        {
            if (LastStatus == NAK)
            {
                if (n == 0)
                {
                    return -1;
                }
                break;
            }
            USB_DBG("token_out result=%d %02x", result, LastStatus);
            return result;
        }
        write_len += result;
        if (result < ep->getSize())
        {
            break;
        }
    }
    return write_len;
}
void USBHALHost::multi_token_inNB(USBEndpoint* ep, uint8_t* data, int size)
{
    //USB_TRACE1(size);
    //USB_TEST_ASSERT(ep->getState() != USB_TYPE_PROCESSING);
    ep->setBuffer(data, size);
    ep->setState(USB_TYPE_PROCESSING);
}

USB_TYPE USBHALHost::multi_token_inNB_result(USBEndpoint* ep)
{
    //USB_TEST_ASSERT(ep->getState() == USB_TYPE_PROCESSING);
    uint8_t* buf = ep->getBufStart();
    int size = ep->getBufSize();
    int result = multi_token_in(ep, buf, size, false);
    //USB_TRACE1(result);
    if (result < 0)
    {
        return USB_TYPE_PROCESSING;
    }
    ep->setLengthTransferred(result);
    ep->setState(USB_TYPE_IDLE);
    return USB_TYPE_OK;

}

void USBHALHost::setToggle(USBEndpoint* ep, uint8_t toggle)
{
    //USB_TEST_ASSERT(toggle == 1);
    ep->setData01(toggle == 0 ? DATA0 : DATA1);
}

int USBHALHost::epint_setup(USBEndpoint* ep)
{
    return 1;
}

void USBHALHost::_usbisr(void)
{
    instHost->usbisr();
}


void USBHALHost::usbisr(void)
{
    USB_OTG_GlobalTypeDef *USBx = hhcd->Instance;
    uint32_t i = 0 , interrupt = 0;

    /* ensure that we are in device mode */
    if (USB_GetMode(hhcd->Instance) == USB_OTG_MODE_HOST)
    {
        /* avoid spurious interrupt */
        if(__HAL_HCD_IS_INVALID_INTERRUPT(hhcd))
        {
            return;
        }

        if(__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_PXFR_INCOMPISOOUT))
        {
            /* incorrect mode, acknowledge the interrupt */
            __HAL_HCD_CLEAR_FLAG(hhcd, USB_OTG_GINTSTS_PXFR_INCOMPISOOUT);
        }

        if(__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_IISOIXFR))
        {
            /* incorrect mode, acknowledge the interrupt */
            __HAL_HCD_CLEAR_FLAG(hhcd, USB_OTG_GINTSTS_IISOIXFR);
        }

        if(__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_PTXFE))
        {
            /* incorrect mode, acknowledge the interrupt */
            __HAL_HCD_CLEAR_FLAG(hhcd, USB_OTG_GINTSTS_PTXFE);
        }

        if(__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_MMIS))
        {
            /* incorrect mode, acknowledge the interrupt */
            __HAL_HCD_CLEAR_FLAG(hhcd, USB_OTG_GINTSTS_MMIS);
        }

        /* Handle Host Disconnect Interrupts */
        if(__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_DISCINT))
        {

            /* Cleanup HPRT */
            USBx_HPRT0 &= ~(USB_OTG_HPRT_PENA | USB_OTG_HPRT_PCDET |\
                            USB_OTG_HPRT_PENCHNG | USB_OTG_HPRT_POCCHNG );

            /* Handle Host Port Interrupts */
            HAL_HCD_Disconnect_Callback(hhcd);
            USB_InitFSLSPClkSel(hhcd->Instance ,HCFG_48_MHZ );
            __HAL_HCD_CLEAR_FLAG(hhcd, USB_OTG_GINTSTS_DISCINT);
        }

        /* Handle Host Port Interrupts */
        if(__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_HPRTINT))
        {
            //
            USB_OTG_GlobalTypeDef *USBx = hhcd->Instance;
            __IO uint32_t hprt0, hprt0_dup;

            /* Handle Host Port Interrupts */
            hprt0 = USBx_HPRT0;
            hprt0_dup = USBx_HPRT0;

            hprt0_dup &= ~(USB_OTG_HPRT_PENA | USB_OTG_HPRT_PCDET |\
                           USB_OTG_HPRT_PENCHNG | USB_OTG_HPRT_POCCHNG );

            /* Check wether Port Connect Detected */
            if((hprt0 & USB_OTG_HPRT_PCDET) == USB_OTG_HPRT_PCDET)
            {
                if((hprt0 & USB_OTG_HPRT_PCSTS) == USB_OTG_HPRT_PCSTS)
                {
                    USB_MASK_INTERRUPT(hhcd->Instance, USB_OTG_GINTSTS_DISCINT);
                    HAL_HCD_Connect_Callback(hhcd);
                }
                hprt0_dup  |= USB_OTG_HPRT_PCDET;

            }

            /* Check whether Port Enable Changed */
            if((hprt0 & USB_OTG_HPRT_PENCHNG) == USB_OTG_HPRT_PENCHNG)
            {
                hprt0_dup |= USB_OTG_HPRT_PENCHNG;

                if((hprt0 & USB_OTG_HPRT_PENA) == USB_OTG_HPRT_PENA)
                {
                    if(hhcd->Init.phy_itface  == USB_OTG_EMBEDDED_PHY)
                    {
                        if ((hprt0 & USB_OTG_HPRT_PSPD) == (HPRT0_PRTSPD_LOW_SPEED << 17))
                        {
                            USB_InitFSLSPClkSel(hhcd->Instance ,HCFG_6_MHZ );
                        }
                        else
                        {
                            USB_InitFSLSPClkSel(hhcd->Instance ,HCFG_48_MHZ );
                        }
                    }
                    else
                    {
                        if(hhcd->Init.speed == HCD_SPEED_FULL)
                        {
                            USBx_HOST->HFIR = (uint32_t)60000;
                        }
                    }
                    HAL_HCD_Connect_Callback(hhcd);

                    if(hhcd->Init.speed == HCD_SPEED_HIGH)
                    {
                        USB_UNMASK_INTERRUPT(hhcd->Instance, USB_OTG_GINTSTS_DISCINT);
                    }
                }
                else
                {
                    /* Cleanup HPRT */
                    USBx_HPRT0 &= ~(USB_OTG_HPRT_PENA | USB_OTG_HPRT_PCDET |\
                                    USB_OTG_HPRT_PENCHNG | USB_OTG_HPRT_POCCHNG );

                    USB_UNMASK_INTERRUPT(hhcd->Instance, USB_OTG_GINTSTS_DISCINT);
                }
            }

            /* Check For an overcurrent */
            if((hprt0 & USB_OTG_HPRT_POCCHNG) == USB_OTG_HPRT_POCCHNG)
            {
                hprt0_dup |= USB_OTG_HPRT_POCCHNG;
            }

            /* Clear Port Interrupts */
            USBx_HPRT0 = hprt0_dup;
        }


        //


        /* Handle Host SOF Interrupts */
        if(__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_SOF))
        {
            HAL_HCD_SOF_Callback(hhcd);
            __HAL_HCD_CLEAR_FLAG(hhcd, USB_OTG_GINTSTS_SOF);
        }

        /* Handle Host channel Interrupts */
        if(__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_HCINT))
        {

            interrupt = USB_HC_ReadInterrupt(hhcd->Instance);
            for (i = 0; i < hhcd->Init.Host_channels ; i++)
            {
                if (interrupt & (1 << i))
                {
                    if ((USBx_HC(i)->HCCHAR) &  USB_OTG_HCCHAR_EPDIR)
                    {
                        //
                        USB_OTG_GlobalTypeDef *USBx = hhcd->Instance;
                        uint8_t chnum = i;
                        if ((USBx_HC(chnum)->HCINT) &  USB_OTG_HCINT_AHBERR)
                        {
                            __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_AHBERR);
                            __HAL_HCD_UNMASK_HALT_HC_INT(chnum);
                        }
                        else if ((USBx_HC(chnum)->HCINT) &  USB_OTG_HCINT_ACK)
                        {
                            __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_ACK);
                        }

                        else if ((USBx_HC(chnum)->HCINT) &  USB_OTG_HCINT_STALL)
                        {
                            __HAL_HCD_UNMASK_HALT_HC_INT(chnum);
                            hhcd->hc[chnum].state = HC_STALL;
                            __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_NAK);
                            __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_STALL);
                            USB_HC_Halt(hhcd->Instance, chnum);
                        }
                        else if ((USBx_HC(chnum)->HCINT) &  USB_OTG_HCINT_DTERR)
                        {
                            __HAL_HCD_UNMASK_HALT_HC_INT(chnum);
                            USB_HC_Halt(hhcd->Instance, chnum);
                            __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_NAK);
                            hhcd->hc[chnum].state = HC_DATATGLERR;
                            __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_DTERR);
                        }

                        if ((USBx_HC(chnum)->HCINT) &  USB_OTG_HCINT_FRMOR)
                        {
                            __HAL_HCD_UNMASK_HALT_HC_INT(chnum);
                            USB_HC_Halt(hhcd->Instance, chnum);
                            __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_FRMOR);
                        }

                        else if ((USBx_HC(chnum)->HCINT) &  USB_OTG_HCINT_XFRC)
                        {

                            if (hhcd->Init.dma_enable)
                            {
                                hhcd->hc[chnum].xfer_count = hhcd->hc[chnum].xfer_len - \
                                                             (USBx_HC(chnum)->HCTSIZ & USB_OTG_HCTSIZ_XFRSIZ);
                            }

                            hhcd->hc[chnum].state = HC_XFRC;
                            __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_XFRC);


                            if ((hhcd->hc[chnum].ep_type == EP_TYPE_CTRL)||
                                    (hhcd->hc[chnum].ep_type == EP_TYPE_BULK))
                            {
                                __HAL_HCD_UNMASK_HALT_HC_INT(chnum);
                                USB_HC_Halt(hhcd->Instance, chnum);
                                __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_NAK);

                            }
                            else if(hhcd->hc[chnum].ep_type == EP_TYPE_INTR)
                            {
                                USBx_HC(chnum)->HCCHAR |= USB_OTG_HCCHAR_ODDFRM;
                                __HAL_HCD_UNMASK_HALT_HC_INT(chnum);
                                USB_HC_Halt(hhcd->Instance, chnum);
                                __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_NAK);
                            }
                            else if(hhcd->hc[chnum].ep_type == EP_TYPE_ISOC)
                            {
                                USBx_HC(chnum)->HCCHAR |= USB_OTG_HCCHAR_ODDFRM;
                                hhcd->hc[chnum].urb_state = URB_DONE;
                                HAL_HCD_HC_NotifyURBChange_Callback(hhcd, chnum, hhcd->hc[chnum].urb_state);
                            }
                            hhcd->hc[chnum].toggle_in ^= 1;

                        }
                        else if ((USBx_HC(chnum)->HCINT) &  USB_OTG_HCINT_CHH)
                        {
                            __HAL_HCD_MASK_HALT_HC_INT(chnum);

                            if(hhcd->hc[chnum].state == HC_XFRC)
                            {
                                hhcd->hc[chnum].urb_state  = URB_DONE;
                            }

                            else if (hhcd->hc[chnum].state == HC_NAK)
                            {
                                hhcd->hc[chnum].urb_state  = URB_DONE;
                            }

                            else if (hhcd->hc[chnum].state == HC_STALL)
                            {
                                hhcd->hc[chnum].urb_state  = URB_STALL;
                            }

                            else if (hhcd->hc[chnum].state == HC_XACTERR)
                            {
                                hhcd->hc[chnum].urb_state = URB_NOTREADY;
                            }

                            else if (hhcd->hc[chnum].state == HC_DATATGLERR)
                            {
                                hhcd->hc[chnum].urb_state = URB_ERROR;
                            }

                            __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_CHH);
                            HAL_HCD_HC_NotifyURBChange_Callback(hhcd, chnum, hhcd->hc[chnum].urb_state);
                        }

                        else if ((USBx_HC(chnum)->HCINT) &  USB_OTG_HCINT_TXERR)
                        {
                            __HAL_HCD_UNMASK_HALT_HC_INT(chnum);
                            hhcd->hc[chnum].state = HC_XACTERR;
                            USB_HC_Halt(hhcd->Instance, chnum);
                            __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_TXERR);
                        }
                        else if ((USBx_HC(chnum)->HCINT) &  USB_OTG_HCINT_NAK)
                        {
                            if(hhcd->hc[chnum].ep_type == EP_TYPE_INTR)
                            {
                                __HAL_HCD_UNMASK_HALT_HC_INT(chnum);
                                USB_HC_Halt(hhcd->Instance, chnum);
                            }
                            else if (hhcd->hc[chnum].ep_type == EP_TYPE_CTRL)
                            {
                                /* re-activate the channel  */
                                USBx_HC(chnum)->HCCHAR &= ~USB_OTG_HCCHAR_CHDIS;
                                USBx_HC(chnum)->HCCHAR |= USB_OTG_HCCHAR_CHENA;

                            }

                            else if (hhcd->hc[chnum].ep_type == EP_TYPE_BULK)
                            {
                                __HAL_HCD_UNMASK_HALT_HC_INT(chnum);
                                USB_HC_Halt(hhcd->Instance, chnum);
                            }

                            hhcd->hc[chnum].state = HC_NAK;
                            __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_NAK);
                        }
                        //
                    }
                    else
                    {
                        //
                        uint8_t chnum=i;
                        USB_OTG_GlobalTypeDef *USBx = hhcd->Instance;

                        if ((USBx_HC(chnum)->HCINT) &  USB_OTG_HCINT_AHBERR)
                        {
                            __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_AHBERR);
                            __HAL_HCD_UNMASK_HALT_HC_INT(chnum);
                        }
                        else if ((USBx_HC(chnum)->HCINT) &  USB_OTG_HCINT_ACK)
                        {
                            __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_ACK);

                            if( hhcd->hc[chnum].do_ping == 1)
                            {
                                hhcd->hc[chnum].state = HC_NYET;
                                __HAL_HCD_UNMASK_HALT_HC_INT(chnum);
                                USB_HC_Halt(hhcd->Instance, chnum);
                                hhcd->hc[chnum].urb_state  = URB_NOTREADY;
                            }
                        }

                        else if ((USBx_HC(chnum)->HCINT) &  USB_OTG_HCINT_NYET)
                        {
                            hhcd->hc[chnum].state = HC_NYET;
                            __HAL_HCD_UNMASK_HALT_HC_INT(chnum);
                            USB_HC_Halt(hhcd->Instance, chnum);
                            __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_NYET);

                        }

                        else if ((USBx_HC(chnum)->HCINT) &  USB_OTG_HCINT_FRMOR)
                        {
                            __HAL_HCD_UNMASK_HALT_HC_INT(chnum);
                            USB_HC_Halt(hhcd->Instance, chnum);
                            __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_FRMOR);
                        }

                        else if ((USBx_HC(chnum)->HCINT) &  USB_OTG_HCINT_XFRC)
                        {
                            __HAL_HCD_UNMASK_HALT_HC_INT(chnum);
                            USB_HC_Halt(hhcd->Instance, chnum);
                            __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_XFRC);
                            hhcd->hc[chnum].state = HC_XFRC;

                        }

                        else if ((USBx_HC(chnum)->HCINT) &  USB_OTG_HCINT_STALL)
                        {
                            __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_STALL);
                            __HAL_HCD_UNMASK_HALT_HC_INT(chnum);
                            USB_HC_Halt(hhcd->Instance, chnum);
                            hhcd->hc[chnum].state = HC_STALL;
                        }

                        else if ((USBx_HC(chnum)->HCINT) &  USB_OTG_HCINT_NAK)
                        {
                            __HAL_HCD_UNMASK_HALT_HC_INT(chnum);
                            USB_HC_Halt(hhcd->Instance, chnum);
                            hhcd->hc[chnum].state = HC_NAK;
                            __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_NAK);
                        }

                        else if ((USBx_HC(chnum)->HCINT) &  USB_OTG_HCINT_TXERR)
                        {
                            __HAL_HCD_UNMASK_HALT_HC_INT(chnum);
                            USB_HC_Halt(hhcd->Instance, chnum);
                            hhcd->hc[chnum].state = HC_XACTERR;
                            __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_TXERR);
                        }

                        else if ((USBx_HC(chnum)->HCINT) &  USB_OTG_HCINT_DTERR)
                        {
                            __HAL_HCD_UNMASK_HALT_HC_INT(chnum);
                            USB_HC_Halt(hhcd->Instance, chnum);
                            __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_NAK);
                            __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_DTERR);
                            hhcd->hc[chnum].state = HC_DATATGLERR;
                        }


                        else if ((USBx_HC(chnum)->HCINT) &  USB_OTG_HCINT_CHH)
                        {
                            __HAL_HCD_MASK_HALT_HC_INT(chnum);

                            if(hhcd->hc[chnum].state == HC_XFRC)
                            {
                                hhcd->hc[chnum].urb_state  = URB_DONE;
                                if (hhcd->hc[chnum].ep_type == EP_TYPE_BULK)
                                {
                                    hhcd->hc[chnum].toggle_out ^= 1;
                                }
                            }
                            else if (hhcd->hc[chnum].state == HC_NAK)
                            {
                                hhcd->hc[chnum].urb_state  = URB_NOTREADY;
                            }

                            else if (hhcd->hc[chnum].state == HC_NYET)
                            {
                                hhcd->hc[chnum].urb_state  = URB_NOTREADY;
                                hhcd->hc[chnum].do_ping = 0;
                            }

                            else if (hhcd->hc[chnum].state == HC_STALL)
                            {
                                hhcd->hc[chnum].urb_state  = URB_STALL;
                            }

                            else if(hhcd->hc[chnum].state == HC_XACTERR)
                            {
                                hhcd->hc[chnum].urb_state = URB_NOTREADY;
                            }

                            else if (hhcd->hc[chnum].state == HC_DATATGLERR)
                            {
                                hhcd->hc[chnum].urb_state = URB_ERROR;
                            }

                            __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_CHH);
                            HAL_HCD_HC_NotifyURBChange_Callback(hhcd, chnum, hhcd->hc[chnum].urb_state);
                        }
                        //
                    }
                }
            }

            __HAL_HCD_CLEAR_FLAG(hhcd, USB_OTG_GINTSTS_HCINT);
        }

        /* Handle Rx Queue Level Interrupts */
        if(__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_RXFLVL))
        {
            USB_MASK_INTERRUPT(hhcd->Instance, USB_OTG_GINTSTS_RXFLVL);

//
            USB_OTG_GlobalTypeDef *USBx = hhcd->Instance;
            uint8_t                       channelnum =0;
            uint32_t                      pktsts;
            uint32_t                      pktcnt;
            uint32_t                      temp = 0;

            temp = hhcd->Instance->GRXSTSP ;
            channelnum = temp &  USB_OTG_GRXSTSP_EPNUM;
            pktsts = (temp &  USB_OTG_GRXSTSP_PKTSTS) >> 17;
            pktcnt = (temp &  USB_OTG_GRXSTSP_BCNT) >> 4;

            switch (pktsts)
            {
            case GRXSTS_PKTSTS_IN:
                /* Read the data into the host buffer. */
                if ((pktcnt > 0) && (hhcd->hc[channelnum].xfer_buff != (void  *)0))
                {

                    USB_ReadPacket(hhcd->Instance, hhcd->hc[channelnum].xfer_buff, pktcnt);

                    /*manage multiple Xfer */
                    hhcd->hc[channelnum].xfer_buff += pktcnt;
                    hhcd->hc[channelnum].xfer_count  += pktcnt;

                    if((USBx_HC(channelnum)->HCTSIZ & USB_OTG_HCTSIZ_PKTCNT) > 0)
                    {
                        /* re-activate the channel when more packets are expected */
                        USBx_HC(channelnum)->HCCHAR &= ~USB_OTG_HCCHAR_CHDIS;
                        USBx_HC(channelnum)->HCCHAR |= USB_OTG_HCCHAR_CHENA;
                        hhcd->hc[channelnum].toggle_in ^= 1;
                    }
                }
                break;

            case GRXSTS_PKTSTS_DATA_TOGGLE_ERR:
                break;
            case GRXSTS_PKTSTS_IN_XFER_COMP:
            case GRXSTS_PKTSTS_CH_HALTED:
            default:
                break;
            }
//

            USB_UNMASK_INTERRUPT(hhcd->Instance, USB_OTG_GINTSTS_RXFLVL);
        }
    }
}



uint8_t HC::slot = 0x00;

HC::HC(HCD_HandleTypeDef* hhcd_USB)
{
    static const int start = 1;
    uint8_t mask = (1<<start);
    hc_USB=hhcd_USB;
    for(int i = start; i < 8; i++, mask <<= 1)
    {
        if (!(slot & mask))
        {
            slot |= mask;
            _ch = i;
            return;
        }
    }
    _ch = 0; // ERROR!!!
}

HC::HC(HCD_HandleTypeDef* hhcd_USB,int ch)
{
    hc_USB=hhcd_USB;
    _ch = ch;
    slot |= (1<<_ch);
}

HC::~HC()
{
    slot &= ~(1<<_ch);
}

HAL_StatusTypeDef HC::Init(int IF_N, uint8_t epnum, uint8_t dev_address, uint8_t speed, uint8_t ep_type, uint16_t mps)
{
    _ep_addr = epnum;
    _ep_type = ep_type;
    if(IF_N!=USB_FastSpeed)
    {
     while(HAL_HCD_GetState(hc_USB)!=HAL_HCD_STATE_READY);
    }
    return HAL_HCD_HC_Init(hc_USB, _ch,
                           epnum, dev_address, speed, ep_type, mps);
}

HAL_StatusTypeDef HC::SubmitRequest(int IF_N,uint8_t* pbuff, uint16_t length, bool setup)
{
    uint32_t tick;
    tick=HAL_GetTick();
    while(HAL_GetTick()==tick);
    if(IF_N!=USB_FastSpeed)
    {
        while((hc_USB->Instance->GRXSTSR&0x1E0000)==0x40000);
        while(((hc_USB->Instance->HNPTXSTS& 0xFFFF)*((hc_USB->Instance->HNPTXSTS& 0x000F0000)>>16))<length);
    }
    uint8_t direction = (_ep_addr & 0x80) ? DIR_IN : DIR_OUT;
    if (_ep_type == EP_TYPE_CTRL)
    {
        HCD_HCTypeDef* hc = &hc_USB->hc[_ch];
        if (setup)
        {
            hc->data_pid = HC_PID_SETUP;
            hc->toggle_out = 0;
        }
        else
        {
            if (direction == DIR_IN)
            {
                if (hc->toggle_in == 0)
                {
                    hc->data_pid = HC_PID_DATA0;
                }
                else
                {
                    hc->data_pid = HC_PID_DATA1;
                }
            }
            else     // OUT
            {
                if (hc->toggle_out == 0)
                {
                    hc->data_pid = HC_PID_DATA0;
                }
                else
                {
                    hc->data_pid = HC_PID_DATA1;
                }
            }
        }
        hc->xfer_buff = pbuff;
        hc->xfer_len  = length;
        hc->urb_state = URB_IDLE;
        hc->xfer_count = 0;
        hc->ch_num = _ch;
        hc->state = HC_IDLE;
        if(IF_N==USB_FastSpeed)
        {
        return USB_HC_StartXfer(hc_USB->Instance, hc, 0);
        }
        else
        {
        return USB_HC_StartXfer(hc_USB->Instance, hc, 1);
        }
    }
    return HAL_HCD_HC_SubmitRequest(hc_USB, _ch,
                                    direction, _ep_type, 0, pbuff, length, 0);
}

HCD_URBStateTypeDef HC::GetURBState()
{
    return HAL_HCD_HC_GetURBState(hc_USB, _ch);
}



HCD_HCStateTypeDef HC::GetState()
{
    return HAL_HCD_HC_GetState(hc_USB, _ch);
}

uint32_t HC::GetXferCount()
{
    return HAL_HCD_HC_GetXferCount(hc_USB, _ch);
}

void HC::SetToggle(uint8_t toggle)
{
    if (_ep_addr & 0x80)   // IN
    {
        hc_USB->hc[_ch].toggle_in = toggle;
    }
    else     // OUT
    {
        hc_USB->hc[_ch].toggle_out = toggle;
    }
}

#endif