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

Revision:
24:5396b6a93262
Child:
25:7d6d9fc471bf
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/TARGET_STM32F7/USBHALHost_F746NG.cpp	Mon Jun 13 17:21:07 2016 +0000
@@ -0,0 +1,1345 @@
+#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
+
+