Simple USBHost library for Nucleo F446RE/F411RE/F401RE FRDM-KL46Z/KL25Z/F64F LPC4088/LPC1768

Dependencies:   FATFileSystem

Dependents:   F401RE-BTstack_example F401RE-USBHostMSD_HelloWorld

Fork of KL46Z-USBHost by Norimasa Okamoto

簡易USBホストライブラリです。
official-USBHostの下位互換で対応プログラムを僅かな修正で動かすことが出来ます。

Platforms

  • Nucleo F446RE
  • Nucleo F411RE
  • Nucleo F401RE
  • FRDM-K64F
  • FRDM-KL46Z
  • FRDM-KL25Z
  • LPC4088
  • LPC1768

Nucleo F446RE/F411RE/F401REのUSB接続方法

ST morphoUSB
U5V (CN10-8)VBUS (1 RED)
PA11 (CN10-14)DM  (2 WHITE)
PA12 (CN10-12)DP  (3 GREEN)
GND (CN10-20)GND (4 BLACK)

Examples

Import programF446RE-USBHostMouse_HelloWorld

USBHostMouse Hello World for ST-Nucleo-F446RE

Import programF401RE-USBHostMSD_HelloWorld

Simple USBHost MSD(USB flash drive) for Nucleo F401RE/FRDM-KL46Z test program

Import programF401RE-USBHostC270_example

Simple USBHost WebCam test program

Import programK64F_USBHostC270_example

Simple USBHost C270 example

Import programF401RE-BTstack_example

BTstack for Nucleo F401RE/FRDM-KL46Z example program

Import programUSBHostRSSI_example

Bluetooth device discovery example program.

Import programKL46Z-USBHostGPS_HelloWorld

Simple USBHost GPS Dongle Receiver for FRDM-KL46Z test program

Files at this revision

API Documentation at this revision

Comitter:
va009039
Date:
Mon Jun 23 20:30:04 2014 +0900
Parent:
15:d14c06cc5c07
Child:
17:4a710e2ba162
Commit message:
add FRDM-K64F.(not tested)

Changed in this revision

USBHost/USBEndpoint.h Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHALHost_F401RE.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHALHost_F401RE.h Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHALHost_KL46Z.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHALHost_KL46Z.h Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHost.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost/myvector.h Show annotated file Show diff for this revision Revisions of this file
USBHostRSSI/USBHostRSSI.cpp Show annotated file Show diff for this revision Revisions of this file
--- a/USBHost/USBEndpoint.h	Fri Jun 13 01:52:44 2014 +0000
+++ b/USBHost/USBEndpoint.h	Mon Jun 23 20:30:04 2014 +0900
@@ -32,6 +32,7 @@
     USBEndpoint(USBDeviceConnected* _dev) {
         init(CONTROL_ENDPOINT, IN, 8, 0);
         dev = _dev;
+        pData = NULL;
     }
 
     /**
@@ -43,7 +44,8 @@
     * @param ep_number endpoint number
     */
     void init(ENDPOINT_TYPE _type, ENDPOINT_DIRECTION _dir, uint32_t size, uint8_t ep_number) {
-        type = _type;
+        setState(USB_TYPE_FREE);
+        setType(_type);
         dir = _dir;
         MaxPacketSize = size;
         address = ep_number;
@@ -81,17 +83,21 @@
         rx.call();
     };
 
+    void setType(ENDPOINT_TYPE _type) { type = _type; }
+    void setState(USB_TYPE st) { state = st; }
     void setDevice(USBDeviceConnected* _dev) { dev = _dev; }
-    void setState(uint8_t st){}; // dummy
     void setBuffer(uint8_t* buf, int size) { buf_start = buf, buf_size = size; }
     void setLengthTransferred(int len) { transferred = len; };
     void setAddress(int addr) { address = addr; }
     void setSize(int size) { MaxPacketSize = size; }
     void setData01(uint8_t data01) { data01_toggle = data01; }
     void setNextEndpoint(USBEndpoint* ep) { nextEp = ep; };
+    template<class T>
+    void setHALData(T data) { pData = data; }
 
     USBDeviceConnected* getDevice() { return dev; }
     ENDPOINT_TYPE getType() { return type; };
+    USB_TYPE getState() { return state; }
     int getLengthTransferred() { return transferred; }
     uint8_t *getBufStart() { return buf_start; }
     int getBufSize() { return buf_size; }
@@ -103,9 +109,13 @@
         data01_toggle = (data01_toggle == DATA0) ? DATA1 : DATA0;
     }
     USBEndpoint* nextEndpoint() { return nextEp; };
+    template<class T>
+    T getHALData() { return reinterpret_cast<T>(pData); }
 
 private:
+    USBEndpoint(){}
     ENDPOINT_TYPE type;
+    USB_TYPE state;
     ENDPOINT_DIRECTION dir;
     USBDeviceConnected* dev;
     uint8_t data01_toggle; // DATA0,DATA1
@@ -116,6 +126,7 @@
     FunctionPointer rx;
     int MaxPacketSize;
     USBEndpoint* nextEp;
+    void* pData;
 };
 
 class EndpointQueue {
@@ -143,3 +154,5 @@
     USBEndpoint* head;
     USBEndpoint* tail;
 };
+
+
--- a/USBHost/USBHALHost_F401RE.cpp	Fri Jun 13 01:52:44 2014 +0000
+++ b/USBHost/USBHALHost_F401RE.cpp	Mon Jun 23 20:30:04 2014 +0900
@@ -1,6 +1,7 @@
 // Simple USBHost for Nucleo F401RE
 #if defined(TARGET_NUCLEO_F401RE)
 #include "USBHALHost_F401RE.h"
+#include <algorithm>
 
 template <bool>struct CtAssert;
 template <>struct CtAssert<true> {};
@@ -9,6 +10,7 @@
 
 #ifdef _USB_DBG
 extern RawSerial pc;
+//RawSerial pc(USBTX,USBRX);
 #include "mydebug.h"
 #define USB_DBG(...) do{pc.printf("[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);pc.printf(__VA_ARGS__);pc.puts("\n");} while(0);
 #define USB_DBG_HEX(A,B) debug_hex<RawSerial>(pc,A,B)
@@ -41,15 +43,13 @@
 #define USB_INFO(...) do{fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");}while(0);
 
 __IO bool attach_done = false;
-__IO bool token_done = false;
-__IO HCD_URBStateTypeDef g_urb_state = URB_IDLE;
 
 void delay_ms(uint32_t t)
 {
     HAL_Delay(t);
 }
 
-// from usbh_conf.c
+// usbh_conf.c
 extern HCD_HandleTypeDef hhcd_USB_OTG_FS;
 
 void HAL_HCD_MspInit(HCD_HandleTypeDef* hhcd)
@@ -79,7 +79,7 @@
   }
 }
 
-// from stm32f4xx_it.c
+// stm32f4xx_it.c
 extern "C" {
 void HAL_HCD_Connect_Callback(HCD_HandleTypeDef *hhcd)
 {
@@ -87,33 +87,8 @@
     attach_done = true;
 }
 
-void HAL_HCD_Disconnect_Callback(HCD_HandleTypeDef *hhcd)
-{
-    USB_TRACE();
-}
-
-void HAL_HCD_HC_NotifyURBChange_Callback(HCD_HandleTypeDef *hhcd, uint8_t chnum, HCD_URBStateTypeDef urb_state)
-{
-    USB_TRACE1(chnum);
-    USB_TRACE1(urb_state);
-    g_urb_state = urb_state;
-    token_done = true;
-}
-
 } // extern "C"
 
-const int CH_CTL_IN  = 0;
-const int CH_CTL_OUT = 1;
-const int CH_INT_IN  = 2;
-const int CH_INT_OUT = 3;
-const int CH_BLK_IN  = 4;
-const int CH_BLK_OUT = 5;
-const int CH_ISO_IN  = 6;
-const int DIR_IN  = 1;
-const int DIR_OUT = 0;
-
-
-
 USBHALHost* USBHALHost::instHost;
 
 USBHALHost::USBHALHost() {
@@ -156,19 +131,19 @@
 }
 
 int USBHALHost::token_setup(USBEndpoint* ep, SETUP_PACKET* setup, uint16_t wLength) {
+    const uint8_t ep_addr = 0x00;
+    HC hc;
     USBDeviceConnected* dev = ep->getDevice();
-
-    HAL_HCD_HC_Init(&hhcd_USB_OTG_FS, CH_CTL_OUT, 0x00, 
+    hc.Init(ep_addr, 
         dev->getAddress(),
         dev->getSpeed() ? HCD_SPEED_LOW : HCD_SPEED_FULL,
         EP_TYPE_CTRL, ep->getSize());
 
     setup->wLength = wLength;
+    hc.SubmitRequest((uint8_t*)setup, 8, true); // PID_SETUP
+    while(hc.GetURBState() == URB_IDLE);
 
-    HAL_HCD_HC_SubmitRequest(&hhcd_USB_OTG_FS, CH_CTL_OUT, DIR_OUT, EP_TYPE_CTRL, 0, (uint8_t*)setup, 8, 0);
-    while(HAL_HCD_HC_GetURBState(&hhcd_USB_OTG_FS, CH_CTL_OUT) == URB_IDLE);
-
-    switch(HAL_HCD_HC_GetURBState(&hhcd_USB_OTG_FS, CH_CTL_OUT)) {
+    switch(hc.GetURBState()) {
         case URB_DONE:
             LastStatus = ACK;
             break;
@@ -177,36 +152,7 @@
             break;
     }
     ep->setData01(DATA1);
-    return HAL_HCD_HC_GetXferCount(&hhcd_USB_OTG_FS, CH_CTL_OUT);
-}
-
-HAL_StatusTypeDef HAL_HCD_HC_SubmitRequest2(HCD_HandleTypeDef *hhcd,
-                                            uint8_t ch_num, 
-                                            uint8_t direction ,
-                                            uint8_t ep_type,  
-                                            uint8_t token, 
-                                            uint8_t* pbuff, 
-                                            uint16_t length,
-                                            uint8_t do_ping) 
-{
-    HCD_HCTypeDef* hc = &(hhcd->hc[ch_num]);
-    hc->ep_is_in = direction;
-    hc->ep_type  = ep_type; 
-
-    if (hc->toggle_in == 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_num;
-  hc->state = HC_IDLE;
-
-  return USB_HC_StartXfer(hhcd->Instance, hc, hhcd->Init.dma_enable);
+    return 8;
 }
 
 int USBHALHost::token_in(USBEndpoint* ep, uint8_t* data, int size, int retryLimit) {
@@ -222,17 +168,20 @@
 }
 
 int USBHALHost::token_ctl_in(USBEndpoint* ep, uint8_t* data, int size, int retryLimit) {
+    const uint8_t ep_addr = 0x80;
+    HC hc;
     USBDeviceConnected* dev = ep->getDevice();
-    HAL_HCD_HC_Init(&hhcd_USB_OTG_FS, CH_CTL_IN, 0x80, 
+    hc.Init(ep_addr, 
         dev->getAddress(),
         dev->getSpeed() ? HCD_SPEED_LOW : HCD_SPEED_FULL,
         EP_TYPE_CTRL, ep->getSize());
-    hhcd_USB_OTG_FS.hc[CH_CTL_IN].toggle_in = (ep->getData01() == DATA0) ? 0 : 1;
+
+    hc.SetToggle((ep->getData01() == DATA0) ? 0 : 1);
 
-    HAL_HCD_HC_SubmitRequest2(&hhcd_USB_OTG_FS, CH_CTL_IN, DIR_IN, EP_TYPE_CTRL, 1, data, size, 0);
-    while(HAL_HCD_HC_GetURBState(&hhcd_USB_OTG_FS, CH_CTL_IN) == URB_IDLE);
+    hc.SubmitRequest(data, size);
+    while(hc.GetURBState() == URB_IDLE);
 
-    switch(HAL_HCD_HC_GetURBState(&hhcd_USB_OTG_FS, CH_CTL_IN)) {
+    switch(hc.GetURBState()) {
         case URB_DONE:
             LastStatus = ACK;
             break;
@@ -241,27 +190,29 @@
             return -1;
     }
     ep->toggleData01();
-    return HAL_HCD_HC_GetXferCount(&hhcd_USB_OTG_FS, CH_CTL_IN);
+    return hc.GetXferCount();
 }
 
 int USBHALHost::token_int_in(USBEndpoint* ep, uint8_t* data, int size) {
+    HC hc;
     USBDeviceConnected* dev = ep->getDevice();
-    HAL_HCD_HC_Init(&hhcd_USB_OTG_FS, CH_INT_IN,
+    hc.Init(
         ep->getAddress(),
         dev->getAddress(),
         dev->getSpeed() ? HCD_SPEED_LOW : HCD_SPEED_FULL,
         EP_TYPE_INTR, ep->getSize());
-    hhcd_USB_OTG_FS.hc[CH_INT_IN].toggle_in = (ep->getData01() == DATA0) ? 0 : 1;
+
+    hc.SetToggle((ep->getData01() == DATA0) ? 0 : 1);
 
-    HAL_HCD_HC_SubmitRequest(&hhcd_USB_OTG_FS, CH_INT_IN, DIR_IN, EP_TYPE_INTR, 1, data, size, 0);
-    while(HAL_HCD_HC_GetURBState(&hhcd_USB_OTG_FS, CH_INT_IN) == URB_IDLE);
-    switch(HAL_HCD_HC_GetURBState(&hhcd_USB_OTG_FS, CH_INT_IN)) {
+    hc.SubmitRequest(data, size);
+    while(hc.GetURBState() == URB_IDLE);
+    switch(hc.GetURBState()) {
         case URB_DONE:
-            switch(HAL_HCD_HC_GetState(&hhcd_USB_OTG_FS, CH_INT_IN)) {
+            switch(hc.GetState()) {
                 case HC_XFRC:
                     LastStatus = ep->getData01();
                     ep->toggleData01();
-                    return HAL_HCD_HC_GetXferCount(&hhcd_USB_OTG_FS, CH_INT_IN);
+                    return hc.GetXferCount();
                 case HC_NAK:
                     LastStatus = NAK;
                     return -1;
@@ -273,26 +224,28 @@
 }
 
 int USBHALHost::token_blk_in(USBEndpoint* ep, uint8_t* data, int size, int retryLimit) {
+    HC hc;
     USBDeviceConnected* dev = ep->getDevice();
+    hc.Init(
+        ep->getAddress(),
+        dev->getAddress(),
+        HCD_SPEED_FULL,
+        EP_TYPE_BULK, ep->getSize());
+
+    hc.SetToggle((ep->getData01() == DATA0) ? 0 : 1);
+
     int retry = 0;
     do {
-        HAL_HCD_HC_Init(&hhcd_USB_OTG_FS, CH_BLK_IN,
-            ep->getAddress(),
-            dev->getAddress(),
-            HCD_SPEED_FULL,
-            EP_TYPE_BULK, ep->getSize());
-        hhcd_USB_OTG_FS.hc[CH_BLK_IN].toggle_in = (ep->getData01() == DATA0) ? 0 : 1;
+        hc.SubmitRequest(data, size);
+        while(hc.GetURBState() == URB_IDLE);
 
-        HAL_HCD_HC_SubmitRequest(&hhcd_USB_OTG_FS, CH_BLK_IN, DIR_IN, EP_TYPE_BULK, 1, data, size, 0);
-        while(HAL_HCD_HC_GetURBState(&hhcd_USB_OTG_FS, CH_BLK_IN) == URB_IDLE);
-
-        switch(HAL_HCD_HC_GetURBState(&hhcd_USB_OTG_FS, CH_BLK_IN)) {
+        switch(hc.GetURBState()) {
             case URB_DONE:
-                switch(HAL_HCD_HC_GetState(&hhcd_USB_OTG_FS, CH_BLK_IN)) {
+                switch(hc.GetState()) {
                     case HC_XFRC:
                         LastStatus = ep->getData01();
                         ep->toggleData01();
-                        return HAL_HCD_HC_GetXferCount(&hhcd_USB_OTG_FS, CH_BLK_IN);
+                        return hc.GetXferCount();
                     case HC_NAK:
                         LastStatus = NAK;
                         if (retryLimit > 0) {
@@ -328,18 +281,21 @@
 }
 
 int USBHALHost::token_ctl_out(USBEndpoint* ep, const uint8_t* data, int size, int retryLimit) {
+    const uint8_t ep_addr = 0x00;
+    HC hc;
     USBDeviceConnected* dev = ep->getDevice();
-        HAL_HCD_HC_Init(&hhcd_USB_OTG_FS, CH_CTL_OUT, 0x00, 
-            dev->getAddress(),
-            dev->getSpeed() ? HCD_SPEED_LOW : HCD_SPEED_FULL,
-            EP_TYPE_CTRL, ep->getSize());
-            hhcd_USB_OTG_FS.hc[CH_CTL_OUT].toggle_out = (ep->getData01() == DATA0) ? 0 : 1;
+    hc.Init(ep_addr, 
+        dev->getAddress(),
+        dev->getSpeed() ? HCD_SPEED_LOW : HCD_SPEED_FULL,
+        EP_TYPE_CTRL, ep->getSize());
+
+    hc.SetToggle((ep->getData01() == DATA0) ? 0 : 1);
 
     do {
-        HAL_HCD_HC_SubmitRequest(&hhcd_USB_OTG_FS, CH_CTL_OUT, DIR_OUT, EP_TYPE_CTRL, 1, (uint8_t*)data, size, 0);
-        while(HAL_HCD_HC_GetURBState(&hhcd_USB_OTG_FS, CH_CTL_OUT) == URB_IDLE);
+        hc.SubmitRequest((uint8_t*)data, size);
+        while(hc.GetURBState() == URB_IDLE);
 
-        switch(HAL_HCD_HC_GetURBState(&hhcd_USB_OTG_FS, CH_CTL_OUT)) {
+        switch(hc.GetURBState()) {
             case URB_DONE:
                 LastStatus = ACK;
                 ep->toggleData01();
@@ -354,19 +310,19 @@
 }
 
 int USBHALHost::token_int_out(USBEndpoint* ep, const uint8_t* data, int size) {
+    HC hc;
     USBDeviceConnected* dev = ep->getDevice();
-    HAL_HCD_HC_Init(&hhcd_USB_OTG_FS, CH_INT_OUT,
+    hc.Init(
         ep->getAddress(),
         dev->getAddress(),
         dev->getSpeed() ? HCD_SPEED_LOW : HCD_SPEED_FULL,
         EP_TYPE_INTR, ep->getSize());
-    hhcd_USB_OTG_FS.hc[CH_INT_OUT].toggle_out = (ep->getData01() == DATA0) ? 0 : 1;
+
+    hc.SetToggle((ep->getData01() == DATA0) ? 0 : 1);
 
-    token_done = false;
-    HAL_HCD_HC_SubmitRequest(&hhcd_USB_OTG_FS, CH_INT_OUT, DIR_OUT, EP_TYPE_INTR, 1, (uint8_t*)data, size, 0);
-    while(!token_done);
-
-    if (HAL_HCD_HC_GetURBState(&hhcd_USB_OTG_FS, CH_INT_OUT) != URB_DONE) {
+    hc.SubmitRequest((uint8_t*)data, size);
+    while(hc.GetURBState() == URB_IDLE);
+    if (hc.GetURBState() != URB_DONE) {
         return -1;
     }
     ep->toggleData01();
@@ -374,20 +330,22 @@
 }
 
 int USBHALHost::token_blk_out(USBEndpoint* ep, const uint8_t* data, int size, int retryLimit) {
+    HC hc;
     USBDeviceConnected* dev = ep->getDevice();
+    hc.Init(
+        ep->getAddress(), dev->getAddress(),
+        HCD_SPEED_FULL, EP_TYPE_BULK, ep->getSize());
+
+    hc.SetToggle((ep->getData01() == DATA0) ? 0 : 1);
+
     int retry = 0;
     do {
-        HAL_HCD_HC_Init(&hhcd_USB_OTG_FS, CH_BLK_OUT,
-            ep->getAddress(), dev->getAddress(),
-            HCD_SPEED_FULL, EP_TYPE_BULK, ep->getSize());
-        hhcd_USB_OTG_FS.hc[CH_BLK_OUT].toggle_out = (ep->getData01() == DATA0) ? 0 : 1;
+        hc.SubmitRequest((uint8_t*)data, size);
+        while(hc.GetURBState() == URB_IDLE);
 
-        HAL_HCD_HC_SubmitRequest(&hhcd_USB_OTG_FS, CH_BLK_OUT, DIR_OUT, EP_TYPE_BULK, 1, (uint8_t*)data, size, 0);
-        while(HAL_HCD_HC_GetURBState(&hhcd_USB_OTG_FS, CH_BLK_OUT) == URB_IDLE);
-
-        switch(HAL_HCD_HC_GetURBState(&hhcd_USB_OTG_FS, CH_BLK_OUT)) {
+        switch(hc.GetURBState()) {
             case URB_DONE:
-                switch(HAL_HCD_HC_GetState(&hhcd_USB_OTG_FS, CH_BLK_OUT)) {
+                switch(hc.GetState()) {
                     case HC_XFRC: // ACK
                         LastStatus = ep->getData01();
                         ep->toggleData01();
@@ -409,17 +367,158 @@
 }
 
 int USBHALHost::token_iso_in(USBEndpoint* ep, uint8_t* data, int size) {
-    static bool init = false;
-    if (!init) {
-        init = true;
+    HC* hc = ep->getHALData<HC*>();
+    if (hc == NULL) {
+        hc = new HC;
+        ep->setHALData<HC*>(hc);
         USBDeviceConnected* dev = ep->getDevice();
-        HAL_HCD_HC_Init(&hhcd_USB_OTG_FS, CH_ISO_IN,
+        hc->Init(
             ep->getAddress(), dev->getAddress(),
             HCD_SPEED_FULL, EP_TYPE_ISOC, ep->getSize());
     }
-    HAL_HCD_HC_SubmitRequest(&hhcd_USB_OTG_FS, CH_ISO_IN, DIR_IN, EP_TYPE_ISOC, 1, data, size, 0);
-    while(HAL_HCD_HC_GetURBState(&hhcd_USB_OTG_FS, CH_ISO_IN) == URB_IDLE);
-    return HAL_HCD_HC_GetXferCount(&hhcd_USB_OTG_FS, CH_ISO_IN);
+    hc->SubmitRequest(data, size);
+    while(hc->GetURBState() == URB_IDLE);
+    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, bool block) {
+    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;
+}
+
+uint8_t HC::slot = 0x00;
+
+HC::HC() {
+    uint8_t mask = 0x01;
+    for(int i = 1; i < 8; i++, mask <<= 1) {
+        if (!(slot & mask)) {
+            slot |= mask;
+            _ch = i;
+            return;
+        }
+    }
+    _ch = 0; // ERROR!!!
+}
+
+HC::HC(int ch) {
+    _ch = ch;
+    slot |= (1<<_ch);
+}
+
+HC::~HC() {
+    slot &= ~(1<<_ch);
+}
+
+HAL_StatusTypeDef HC::Init(uint8_t epnum, uint8_t dev_address, uint8_t speed, uint8_t ep_type, uint16_t mps) {
+    _ep_addr = epnum;
+    _ep_type = ep_type;
+    return HAL_HCD_HC_Init(&hhcd_USB_OTG_FS, _ch,
+                           epnum, dev_address, speed, ep_type, mps);
+}
+
+HAL_StatusTypeDef HC::SubmitRequest(uint8_t* pbuff, uint16_t length, bool setup) {
+    uint8_t direction = (_ep_addr & 0x80) ? DIR_IN : DIR_OUT;
+    if (_ep_type == EP_TYPE_CTRL) {
+        HCD_HCTypeDef* hc = &hhcd_USB_OTG_FS.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;
+  
+        return USB_HC_StartXfer(hhcd_USB_OTG_FS.Instance, hc, 0);
+    }
+    return HAL_HCD_HC_SubmitRequest(&hhcd_USB_OTG_FS, _ch,
+                                    direction, _ep_type, 0, pbuff, length, 0);
+}
+
+HCD_URBStateTypeDef HC::GetURBState() {
+    return HAL_HCD_HC_GetURBState(&hhcd_USB_OTG_FS, _ch);
+}
+
+HCD_HCStateTypeDef HC::GetState() {
+    return HAL_HCD_HC_GetState(&hhcd_USB_OTG_FS, _ch);
+}
+
+uint32_t HC::GetXferCount() {
+    return HAL_HCD_HC_GetXferCount(&hhcd_USB_OTG_FS, _ch);
+}
+
+void HC::SetToggle(uint8_t toggle) {
+    if (_ep_addr & 0x80) { // IN
+        hhcd_USB_OTG_FS.hc[_ch].toggle_in = toggle;
+    } else { // OUT
+        hhcd_USB_OTG_FS.hc[_ch].toggle_out = toggle;
+    }
 }
 
 #endif
--- a/USBHost/USBHALHost_F401RE.h	Fri Jun 13 01:52:44 2014 +0000
+++ b/USBHost/USBHALHost_F401RE.h	Mon Jun 23 20:30:04 2014 +0900
@@ -12,6 +12,29 @@
     uint16_t wLength;
 };
 
+class HC {
+    static const uint8_t DIR_IN  = 1;
+    static const uint8_t DIR_OUT = 0;
+
+public:
+    HC();
+    HC(int ch);
+    ~HC();
+    HAL_StatusTypeDef Init(uint8_t epnum, uint8_t dev_address, uint8_t speed, uint8_t ep_type, uint16_t mps);
+    HAL_StatusTypeDef SubmitRequest(uint8_t* pbuff, uint16_t length, bool setup = false);
+    HCD_URBStateTypeDef GetURBState();
+    HCD_HCStateTypeDef GetState();
+    uint32_t GetXferCount();
+    void SetToggle(uint8_t toggle);
+
+    static uint8_t slot;
+
+private:
+    int _ch;
+    uint8_t _ep_addr;
+    uint8_t _ep_type;
+};
+
 class USBHALHost {
 public:
     uint8_t LastStatus;
@@ -25,12 +48,14 @@
     void setEndpoint(){}
     void token_transfer_init(){}
     int token_setup(USBEndpoint* ep, SETUP_PACKET* setup, uint16_t wLength = 0);
+    int token_iso_in(USBEndpoint* ep, uint8_t* data, int size);
+    void token_ready(){}
+    int multi_token_in(USBEndpoint* ep, uint8_t* data = NULL, size_t total = 0, bool block = true);
+    int multi_token_out(USBEndpoint* ep, const uint8_t* data = NULL, size_t total = 0, bool block = true);
+
+private:
     int token_in(USBEndpoint* ep, uint8_t* data = NULL, int size = 0, int retryLimit = 10);
     int token_out(USBEndpoint* ep, const uint8_t* data = NULL, int size = 0, int retryLimit = 10);
-    int token_iso_in(USBEndpoint* ep, uint8_t* data, int size);
-    void token_ready(){}
-
-private:
     int token_ctl_in(USBEndpoint* ep, uint8_t* data, int size, int retryLimit);
     int token_int_in(USBEndpoint* ep, uint8_t* data, int size);
     int token_blk_in(USBEndpoint* ep, uint8_t* data, int size, int retryLimit);
--- a/USBHost/USBHALHost_KL46Z.cpp	Fri Jun 13 01:52:44 2014 +0000
+++ b/USBHost/USBHALHost_KL46Z.cpp	Mon Jun 23 20:30:04 2014 +0900
@@ -1,6 +1,7 @@
 // Simple USBHost for FRDM-KL46Z
 #if defined(TARGET_KL46Z)||defined(TARGET_KL25Z)
 #include "USBHALHost_KL46Z.h"
+#include <algorithm>
 
 template <bool>struct CtAssert;
 template <>struct CtAssert<true> {};
@@ -70,6 +71,10 @@
     // Disable IRQ
     NVIC_DisableIRQ(USB0_IRQn);
 
+#if defined(TARGET_K64F)
+    MPU->CESR=0;
+#endif
+
     // choose usb src as PLL
     SIM->SOPT2 |= (SIM_SOPT2_USBSRC_MASK | SIM_SOPT2_PLLFLLSEL_MASK);
 
@@ -337,6 +342,61 @@
     USB0->ISTAT |= USB_ISTAT_SOFTOK_MASK; // clear SOF
 }
 
+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, bool block) {
+    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::_usbisr(void) {
     if (instHost) {
         instHost->UsbIrqhandler();
--- a/USBHost/USBHALHost_KL46Z.h	Fri Jun 13 01:52:44 2014 +0000
+++ b/USBHost/USBHALHost_KL46Z.h	Mon Jun 23 20:30:04 2014 +0900
@@ -54,11 +54,14 @@
     void setEndpoint();
     void token_transfer_init();
     int token_setup(USBEndpoint* ep, SETUP_PACKET* setup, uint16_t wLength = 0);
+    int multi_token_in(USBEndpoint* ep, uint8_t* data = NULL, size_t total = 0, bool block = true);
+    int multi_token_out(USBEndpoint* ep, const uint8_t* data = NULL, size_t total = 0, bool block = true);
+    int token_iso_in(USBEndpoint* ep, uint8_t* data, int size);
+    void token_ready();
+
+private:
     int token_in(USBEndpoint* ep, uint8_t* data = NULL, int size = 0, int retryLimit = 10);
     int token_out(USBEndpoint* ep, const uint8_t* data = NULL, int size = 0, int retryLimit = 10);
-    int token_iso_in(USBEndpoint* ep, uint8_t* data, int size);
-    void token_ready();
-private:
     static void _usbisr(void);
     void UsbIrqhandler();
     __IO bool attach_done;
--- a/USBHost/USBHost.cpp	Fri Jun 13 01:52:44 2014 +0000
+++ b/USBHost/USBHost.cpp	Mon Jun 23 20:30:04 2014 +0900
@@ -1,6 +1,4 @@
-// Simple USBHost for FRDM-KL46Z
 #include "USBHost.h"
-#include <algorithm>
 
 USBHost* USBHost::inst = NULL;
 
@@ -252,22 +250,12 @@
         USB_DBG("setup %02x", LastStatus);
         return -1;
     }
-    int read_len = 0;
-    while(read_len < size) {
-        int size2 = std::min(size-read_len, ep->getSize());
-        int result = token_in(ep, data+read_len, size2);
-        //USB_DBG("token_in result=%d %02x", result, LastStatus);
-        if (result < 0) {
-            USB_DBG("token_in %d/%d %02x", read_len, size, LastStatus);
-            return result;
-        }
-        read_len += result;
-        if (result < ep->getSize()) {
-            break;
-        }
-    }    
+    int read_len = multi_token_in(ep, data, size);
+    if (read_len < 0) {
+        return -1;
+    }
     ep->setData01(DATA1);
-    int result = token_out(ep); // status stage
+    int result = multi_token_out(ep); // status stage
     if (result < 0) {
         USB_DBG("status token_out %02x", LastStatus);
         if (LastStatus == STALL) {
@@ -292,13 +280,13 @@
     }
     int write_len = 0;
     if (data != NULL) {
-        write_len = token_out(ep, data, size);
+        write_len = multi_token_out(ep, data, size);
         if (write_len < 0) {
             return -1;
         }
     }
     ep->setData01(DATA1);
-    int result = token_in(ep); // status stage
+    int result = multi_token_in(ep); // status stage
     if (result < 0) {
         USB_DBG("result=%d %02x", result, LastStatus);
         //return result;
@@ -314,25 +302,10 @@
     USB_TEST_ASSERT(dev);
     setAddr(dev->getAddress(), dev->getSpeed());
     setEndpoint();
-    const int retryLimit = 0;
-    int read_len = 0;
-    for(int n = 0; read_len < size; n++) {
-        int size2 = std::min(size-read_len, ep->getSize());
-        int result = token_in(ep, data+read_len, size2, retryLimit);
-        if (result < 0) {
-            if (LastStatus == NAK) {
-                if (n == 0) {
-                    return -1;
-                }
-                break;
-            }
-            //USB_DBG("token_in result=%d %02x", result, LastStatus);
-            return result;
-        }
-        read_len += result;
-        if (result < ep->getSize()) {
-            break;
-        }
+    const bool block = false;
+    int read_len = multi_token_in(ep, data, size, block);
+    if (read_len < 0) {
+        return -1;
     }
     ep->setLengthTransferred(read_len);
     return read_len;
@@ -345,25 +318,10 @@
     USB_TEST_ASSERT(dev);
     setAddr(dev->getAddress(), dev->getSpeed());
     setEndpoint();
-    const int retryLimit = 0;
-    int transferred_len = 0;
-    for(int n = 0; transferred_len < size; n++) {
-        int size2 = std::min(size-transferred_len, ep->getSize());
-        int result = token_out(ep, data+transferred_len, size2, retryLimit);
-        if (result < 0) {
-            if (LastStatus == NAK) {
-                if (n == 0) {
-                    return -1;
-                }
-                break;
-            }
-            //USB_DBG("token_in result=%d %02x", result, LastStatus);
-            return result;
-        }
-        transferred_len += result;
-        if (result < ep->getSize()) {
-            break;
-        }
+    const bool block = true;
+    int transferred_len = multi_token_out(ep, data, size, block);
+    if (transferred_len < 0) {
+        return -1;
     }
     ep->setLengthTransferred(transferred_len);
     return transferred_len;
@@ -380,30 +338,10 @@
     USB_TEST_ASSERT(dev);
     setAddr(dev->getAddress());
     setEndpoint();
-    int retryLimit = (timeout_ms == 0) ? 0 : 10;
-    int read_len = 0;
-    Timer t;
-    for(int n = 0; read_len < size; n++) {
-        int size2 = std::min(size-read_len, ep->getSize());
-        int result = token_in(ep, data+read_len, size2, retryLimit);
-        if (result < 0) {
-            if (LastStatus == NAK) {
-                if (n == 0) {
-                    return -1;
-                }
-                break;
-            }
-            //USB_DBG("token_in result=%d %02x", result, LastStatus);
-            return result;
-        }
-        read_len += result;
-        if (result < ep->getSize()) {
-            break;
-        }
-        if (timeout_ms > 0 && t.read_ms() > timeout_ms) {
-            USB_DBG("timeout_ms: %d", timeout_ms);
-            break;
-        }
+    bool block = (timeout_ms != 0);
+    int read_len = multi_token_in(ep, data, size, block);
+    if (read_len < 0) {
+        return -1;
     }
     ep->setLengthTransferred(read_len);
     return read_len;
@@ -415,24 +353,9 @@
     USB_TEST_ASSERT(dev);
     setAddr(dev->getAddress());
     setEndpoint();
-    int write_len = 0;
-    for(int n = 0; write_len < size; n++) {
-        int size2 = std::min(size-write_len, ep->getSize());
-        int result = token_out(ep, data+write_len, size2);
-        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;
-        }
+    int write_len = multi_token_out(ep, data, size);
+    if (write_len < 0) {
+        return -1;
     }
     ep->setLengthTransferred(write_len);
     return write_len;
--- a/USBHost/myvector.h	Fri Jun 13 01:52:44 2014 +0000
+++ b/USBHost/myvector.h	Mon Jun 23 20:30:04 2014 +0900
@@ -7,6 +7,11 @@
         m_size = 0;
         m_buf = NULL;
     }
+    ~myvector() {
+        if (m_buf) {
+            delete[] m_buf;
+        }
+    }
     void push_back(T v) {
         T* new_buf = new T[m_size+1];
         if (m_size > 0) {
--- a/USBHostRSSI/USBHostRSSI.cpp	Fri Jun 13 01:52:44 2014 +0000
+++ b/USBHostRSSI/USBHostRSSI.cpp	Mon Jun 23 20:30:04 2014 +0900
@@ -108,6 +108,8 @@
                         wait_ms(500);
                         rc = cmdSend(HCI_OP_WRITE_INQUIRY_MODE, "B", 0x01); // with RSSI
                         USB_TEST_ASSERT(rc == USB_TYPE_OK);
+                        if (rc != USB_TYPE_OK) {
+                        }
                         break;
                     case HCI_OP_WRITE_INQUIRY_MODE:
                         rc = cmdSend(HCI_OP_PERIODIC_INQUIRY, "HHBBBBB",