Fork of [[https://os.mbed.com/users/va009039/code/F401RE-USBHost/]]. Added support for Seeed Arch Max and STM32F407.

Dependents:   STM32F407VET6_USBHostMSD STM32F407VET6_USBHostMouse STM32F407VET6_USBHostKeyboard STM32F407VET6_USBHostMSD_1

Files at this revision

API Documentation at this revision

Comitter:
hudakz
Date:
Tue Feb 19 21:32:56 2019 +0000
Commit message:
Fork of [[https://os.mbed.com/users/va009039/code/F401RE-USBHost/]]. Added support for Seeed Arch Max and STM32F407.

Changed in this revision

USBHost-STM32F4/USBHost/IUSBEnumerator.h Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHost/USBDeviceConnected.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHost/USBDeviceConnected.h Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHost/USBEndpoint.h Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHost/USBHALHost.h Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHost/USBHALHost2_F401RE.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHost/USBHALHost2_LPC4088.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHost/USBHALHost_F401RE.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHost/USBHALHost_F401RE.h Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHost/USBHALHost_KL46Z.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHost/USBHALHost_KL46Z.h Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHost/USBHALHost_LPC4088.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHost/USBHALHost_LPC4088.h Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHost/USBHost.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHost/USBHost.h Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHost/USBHostConf.h Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHost/USBHostHub.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHost/USBHostTypes.h Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHost/dbg.h Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHost/mydebug.h Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHost/mymap.h Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHost/myvector.h Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHostC270/BaseUvc.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHostC270/BaseUvc.h Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHostC270/CamInfo.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHostC270/USBHostCam.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHostC270/USBHostCam.h Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHostC270/decodeMJPEG.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHostC270/decodeMJPEG.h Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHostGPS/USBHostGPS.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHostGPS/USBHostGPS.h Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHostGPS/decodeNMEA.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHostGPS/decodeNMEA.h Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHostHID/USBHostGamepad.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHostHID/USBHostGamepad.h Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHostHID/USBHostKeyboard.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHostHID/USBHostKeyboard.h Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHostHID/USBHostMouse.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHostHID/USBHostMouse.h Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHostMSD/USBHostMSD.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHostMSD/USBHostMSD.h Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHostRSSI/USBHostRSSI.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost-STM32F4/USBHostRSSI/USBHostRSSI.h Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/IUSBEnumerator.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHost/IUSBEnumerator.h	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,36 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IUSBENUMERATOR_H_
+#define IUSBENUMERATOR_H_
+
+#include "stdint.h"
+#include "USBEndpoint.h"
+
+/*
+Generic interface to implement for "smart" USB enumeration
+*/
+
+class IUSBEnumerator
+{
+public:
+    virtual void setVidPid(uint16_t vid, uint16_t pid) = 0;
+    virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) = 0; //Must return true if the interface should be parsed
+    virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) = 0; //Must return true if the endpoint will be used
+};
+
+#endif /*IUSBENUMERATOR_H_*/
+
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/USBDeviceConnected.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHost/USBDeviceConnected.cpp	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,89 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "USBDeviceConnected.h"
+#include "dbg.h"
+
+USBDeviceConnected::USBDeviceConnected() {
+    init();
+}
+
+void USBDeviceConnected::init() {
+    port = 0;
+    vid = 0;
+    pid = 0;
+    nb_interf = 0;
+    enumerated = false;
+    device_class = 0;
+    device_subclass = 0;
+    proto = 0;
+    lowSpeed = false;
+    hub_parent = NULL;
+}
+
+bool USBDeviceConnected::addInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) {
+    USB_DBG("intf_nb=%d", intf_nb);
+    if (intf.count(intf_nb) > 0) {
+        return false;
+    }
+    intf[intf_nb] = new INTERFACE(intf_class, intf_subclass, intf_protocol);
+    return true;
+}
+
+bool USBDeviceConnected::addEndpoint(uint8_t intf_nb, USBEndpoint * ept) {
+    if (intf.count(intf_nb) > 0) {
+        intf[intf_nb]->ep.push_back(ept);
+        return true;
+    }
+    return false;
+}
+
+void USBDeviceConnected::init(USBDeviceConnected* parent, uint8_t port_, bool lowSpeed_) {
+    USB_DBG("init dev: %p", this);
+    init();
+    hub_parent = parent;
+    port = port_;
+    lowSpeed = lowSpeed_;
+}
+
+void USBDeviceConnected::disconnect() {
+    //for(int i = 0; i < MAX_INTF; i++) {
+    //    intf[i].detach.call();
+    //}
+    //init();
+}
+
+
+USBEndpoint * USBDeviceConnected::getEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir, uint8_t index) {
+    USB_DBG("intf_nb=%d", intf_nb);
+    USB_TEST_ASSERT(intf.count(intf_nb) > 0);
+    INTERFACE* inter = intf[intf_nb];
+    for (int i = 0; i < inter->ep.size(); i++) {
+        if ((inter->ep[i]->getType() == type) && (inter->ep[i]->getDir() == dir)) {
+            if(index) {
+                index--;
+            } else {
+                return inter->ep[i];
+            }
+        }
+    }
+    return NULL;
+}
+
+USBEndpoint * USBDeviceConnected::getEndpoint(uint8_t intf_nb, uint8_t index) {
+    USB_TEST_ASSERT(intf.count(intf_nb) > 0);
+    return intf[intf_nb]->ep[index];
+}
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/USBDeviceConnected.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHost/USBDeviceConnected.h	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,133 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include "USBEndpoint.h"
+#include "USBHostConf.h"
+#include "myvector.h"
+#include "mymap.h"
+
+class USBEndpoint;
+
+struct INTERFACE {
+    INTERFACE(uint8_t _class, uint8_t _subclass, uint8_t _protocol) {
+        intf_class = _class;
+        intf_subclass = _subclass;
+        intf_protocol = _protocol;
+    }
+    uint8_t intf_class;
+    uint8_t intf_subclass;
+    uint8_t intf_protocol;
+    myvector<USBEndpoint*>ep; 
+}; 
+
+/**
+* USBDeviceConnected class
+*/
+class USBDeviceConnected {
+public:
+
+    /**
+    * Constructor
+    */
+    USBDeviceConnected();
+
+    /**
+    * Attach an USBEndpoint to this device
+    *
+    * @param intf_nb interface number
+    * @param ep pointeur on the USBEndpoint which will be attached
+    * @returns true if successful, false otherwise
+    */
+    bool addEndpoint(uint8_t intf_nb, USBEndpoint * ep);
+
+    /**
+    * Retrieve an USBEndpoint by its TYPE and DIRECTION
+    *
+    * @param intf_nb the interface on which to lookup the USBEndpoint
+    * @param type type of the USBEndpoint looked for
+    * @param dir direction of the USBEndpoint looked for
+    * @param index the index of the USBEndpoint whitin the interface
+    * @returns pointer on the USBEndpoint if found, NULL otherwise
+    */
+    USBEndpoint * getEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir, uint8_t index = 0);
+
+    /**
+    * Retrieve an USBEndpoint by its index
+    *
+    * @param intf_nb interface number
+    * @param index index of the USBEndpoint
+    * @returns pointer on the USBEndpoint if found, NULL otherwise
+    */
+    USBEndpoint * getEndpoint(uint8_t intf_nb, uint8_t index);
+
+    /**
+    * Add a new interface to this device
+    *
+    * @param intf_nb interface number
+    * @param intf_class interface class
+    * @param intf_subclass interface subclass
+    * @param intf_protocol interface protocol
+    * @returns true if successful, false otherwise
+    */
+    bool addInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol);
+
+    /**
+    * Disconnect the device by calling a callback function registered by a driver
+    */
+    void disconnect();
+
+    void init(USBDeviceConnected* parent, uint8_t _port, bool _lowSpeed);
+    void setAddress(uint8_t addr_) { addr = addr_; };
+    void setVid(uint16_t vid_) { vid = vid_; };
+    void setPid(uint16_t pid_) { pid = pid_; };
+    void setClass(uint8_t device_class_) { device_class = device_class_; }
+    void setSubClass(uint8_t device_subclass_) { device_subclass = device_subclass_; };
+    void setProtocol(uint8_t pr) { proto = pr; };
+    void setEnumerated() { enumerated = true; };
+    void setNbIntf(uint8_t nb_intf) {nb_interf = nb_intf; };
+    void setSpeed(bool _lowSpeed) { lowSpeed = _lowSpeed; }
+    void setName(const char * name_, uint8_t intf_nb) { return; };
+    void setEpCtl(USBEndpoint* ep) { ep_ctl = ep; }
+
+    static int getNewAddress() {
+        static int addr = 1;
+        return addr++;
+    }
+    uint8_t getAddress() { return addr; };
+    uint16_t getVid() { return vid; };
+    uint16_t getPid() { return pid; };
+    uint8_t getClass() { return device_class; };
+    bool getSpeed() { return lowSpeed; }
+    bool isEnumerated() { return enumerated; };
+    USBEndpoint* getEpCtl() { return ep_ctl; }
+
+private:
+    USBDeviceConnected* hub_parent;
+    mymap<int,INTERFACE*>intf;
+    uint8_t port;
+    uint16_t vid;
+    uint16_t pid;
+    uint8_t addr;
+    uint8_t device_class;
+    uint8_t device_subclass;
+    uint8_t proto;
+    bool lowSpeed;
+    bool enumerated;
+    uint8_t nb_interf;
+    USBEndpoint* ep_ctl;
+    void init();
+};
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/USBEndpoint.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHost/USBEndpoint.h	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,167 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+#pragma once
+#include "FunctionPointer.h"
+#include "USBHostTypes.h"
+#include "USBDeviceConnected.h"
+
+class USBDeviceConnected;
+
+/**
+* USBEndpoint class
+*/
+class USBEndpoint {
+public:
+    /**
+    * Constructor
+    */
+    USBEndpoint(USBDeviceConnected* _dev) {
+        init(CONTROL_ENDPOINT, IN, 8, 0);
+        dev = _dev;
+        pData = NULL;
+    }
+
+    /**
+    * Initialize an endpoint
+    *
+    * @param type endpoint type
+    * @param dir endpoint direction
+    * @param size endpoint size
+    * @param ep_number endpoint number
+    */
+    void init(ENDPOINT_TYPE _type, ENDPOINT_DIRECTION _dir, uint32_t size, uint8_t ep_number) {
+        setState(USB_TYPE_FREE);
+        setType(_type);
+        dir = _dir;
+        MaxPacketSize = size;
+        address = ep_number;
+        data01_toggle = DATA0;
+    }
+
+    void ohci_init(uint8_t frameCount, uint8_t queueLimit) {
+        ohci.frameCount = frameCount;
+        ohci.queueLimit = queueLimit;
+    }
+
+    /**
+     *  Attach a member function to call when a transfer is finished
+     *
+     *  @param tptr pointer to the object to call the member function on
+     *  @param mptr pointer to the member function to be called
+     */
+    template<typename T>
+    inline void attach(T* tptr, void (T::*mptr)(void)) {
+        if((mptr != NULL) && (tptr != NULL)) {
+            rx.attach(tptr, mptr);
+        }
+    }
+
+    /**
+     * Attach a callback called when a transfer is finished
+     *
+     * @param fptr function pointer
+     */
+    inline void attach(void (*fptr)(void)) {
+        if(fptr != NULL) {
+            rx.attach(fptr);
+        }
+    }
+
+    /**
+    * Call the handler associted to the end of a transfer
+    */
+    inline void call() {
+        rx.call();
+    };
+
+    void setType(ENDPOINT_TYPE _type) { type = _type; }
+    void setState(USB_TYPE st) { state = st; }
+    void setDevice(USBDeviceConnected* _dev) { dev = _dev; }
+    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; }
+    uint8_t getAddress(){ return address; };
+    int getSize() { return MaxPacketSize; }
+    ENDPOINT_DIRECTION getDir() { return dir; }
+    uint8_t getData01() { return data01_toggle; }
+    void toggleData01() {
+        data01_toggle = (data01_toggle == DATA0) ? DATA1 : DATA0;
+    }
+    USBEndpoint* nextEndpoint() { return nextEp; };
+    template<class T>
+    T getHALData() { return reinterpret_cast<T>(pData); }
+
+    struct {
+        uint8_t queueLimit;
+        uint8_t frameCount; // 1-8
+    } ohci;
+private:
+    USBEndpoint(){}
+    ENDPOINT_TYPE type;
+    USB_TYPE state;
+    ENDPOINT_DIRECTION dir;
+    USBDeviceConnected* dev;
+    uint8_t data01_toggle; // DATA0,DATA1
+    uint8_t address;
+    int transferred;
+    uint8_t * buf_start;
+    int buf_size;
+    FunctionPointer rx;
+    int MaxPacketSize;
+    USBEndpoint* nextEp;
+    void* pData;
+};
+
+class EndpointQueue {
+public:
+    EndpointQueue():head(NULL),tail(NULL) {}
+    void push(USBEndpoint* ep) {
+        if (head) {
+            tail->setNextEndpoint(ep);
+        } else {
+            head = ep;
+        }
+        tail = ep;
+        ep->setNextEndpoint(NULL);
+    }
+    USBEndpoint* pop() {
+        USBEndpoint* ep = head;
+        if (ep) {
+            head = ep->nextEndpoint();
+        }
+        return ep;
+    }
+    bool empty() { return head == NULL; }
+
+private:
+    USBEndpoint* head;
+    USBEndpoint* tail;
+};
+
+
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/USBHALHost.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHost/USBHALHost.h	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,34 @@
+#include "mbed.h"
+
+struct SETUP_PACKET {
+    uint8_t bmRequestType;
+    uint8_t bRequest;
+    uint16_t wValue;
+    uint16_t wIndex;
+    uint16_t wLength;
+    SETUP_PACKET(uint8_t RequestType, uint8_t Request, uint16_t Value, uint16_t Index, uint16_t Length) {
+        bmRequestType = RequestType;
+        bRequest = Request;
+        wValue = Value;
+        wIndex = Index;
+        wLength = Length;
+    }
+};
+
+#if defined(TARGET_NUCLEO_F401RE)||defined(TARGET_NUCLEO_F411RE)||defined(TARGET_NUCLEO_F446RE)||defined(TARGET_ARCH_MAX)
+#include "USBHALHost_F401RE.h"
+#elif defined(TARGET_KL46Z)||defined(TARGET_KL25Z)||defined(TARGET_K64F)
+#include "USBHALHost_KL46Z.h"
+#elif defined(TARGET_LPC4088)||defined(TARGET_LPC1768)
+#include "USBHALHost_LPC4088.h"
+#else
+#error "target error"
+#endif
+
+#ifndef  CTASSERT
+template <bool>struct CtAssert;
+template <>struct CtAssert<true> {};
+#define CTASSERT(A) CtAssert<A>();
+#endif // CTASSERT
+
+
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/USBHALHost2_F401RE.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHost/USBHALHost2_F401RE.cpp	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,16 @@
+#if defined(TARGET_NUCLEO_F401RE)||defined(TARGET_NUCLEO_F411RE)||defined(TARGET_NUCLEO_F446RE)||defined(TARGET_ARCH_MAX)
+#include "USBHALHost.h"
+
+// usbh_conf.c
+HCD_HandleTypeDef hhcd_USB_OTG_FS;
+
+extern "C" {
+void OTG_FS_IRQHandler(void)
+{
+  HAL_NVIC_ClearPendingIRQ(OTG_FS_IRQn);
+  HAL_HCD_IRQHandler(&hhcd_USB_OTG_FS);
+}
+}
+
+#endif
+
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/USBHALHost2_LPC4088.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHost/USBHALHost2_LPC4088.cpp	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,205 @@
+#if defined(TARGET_LPC4088)||defined(TARGET_LPC1768)
+#include "USBHALHost.h"
+
+#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_INFO(...) do{fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");}while(0);
+
+//#define DBG_USE_POSIX_MEMALIGN
+
+#ifdef DBG_USE_POSIX_MEMALIGN
+void* usb_ram_malloc(size_t size, int aligment)
+{
+    TEST_ASSERT(aligment >= 4);
+    TEST_ASSERT(!(aligment & 3));
+    void* p;
+    if (posix_memalign(&p, aligment, size) == 0) {
+        return p;
+    }
+    return NULL;
+}
+
+void usb_ram_free(void* p)
+{
+    free(p);
+}
+#else
+
+#define CHUNK_SIZE 64
+
+#if defined(TARGET_LPC1768)
+#define USB_RAM_BASE 0x2007C000
+#define USB_RAM_SIZE 0x4000
+#define BLOCK_COUNT (USB_RAM_SIZE/CHUNK_SIZE)
+#elif defined(TARGET_LPC4088)
+#define USB_RAM_BASE 0x20000000
+#define USB_RAM_SIZE 0x4000
+#define BLOCK_COUNT (USB_RAM_SIZE/CHUNK_SIZE)
+#else
+#error "target error"
+#endif
+
+static uint8_t* ram = NULL;
+static uint8_t* map;
+
+static void usb_ram_init()
+{
+    USB_INFO("USB_RAM: 0x%p(%d)", USB_RAM_BASE, USB_RAM_SIZE);
+    ram = (uint8_t*)USB_RAM_BASE;
+    USB_TEST_ASSERT((int)ram%256 == 0);
+    map = (uint8_t*)malloc(BLOCK_COUNT);
+    USB_TEST_ASSERT(map);
+    memset(map, 0, BLOCK_COUNT);
+}
+
+// first fit malloc
+void* usb_ram_malloc(size_t size, int aligment)
+{
+    USB_TEST_ASSERT(aligment >= 4);
+    USB_TEST_ASSERT(!(aligment & 3));
+    if (ram == NULL) {
+        usb_ram_init();
+    }
+    int needs = (size+CHUNK_SIZE-1)/CHUNK_SIZE;
+    void* p = NULL;
+    for(int idx = 0; idx < BLOCK_COUNT;) {
+        bool found = true;
+        for(int i = 0; i < needs; i++) {
+            int block = map[idx + i];
+            if (block != 0) {
+                idx += block;
+                found = false;
+                break;
+            }
+        }
+        if (!found) {
+            continue;
+        }
+        p = ram+idx*CHUNK_SIZE;
+        if ((int)p % aligment) {
+            idx++;
+            continue;
+        }
+        USB_TEST_ASSERT((idx + needs) <= BLOCK_COUNT);
+        for(int i = 0; i < needs; i++) {
+            map[idx + i] = needs - i;
+        }
+        break;
+    }
+    USB_TEST_ASSERT(p);
+    return p;
+}
+
+void usb_ram_free(void* p)
+{
+    USB_TEST_ASSERT(p >= ram);
+    USB_TEST_ASSERT(p < (ram+CHUNK_SIZE*BLOCK_COUNT));
+    int idx = ((int)p-(int)ram)/CHUNK_SIZE;
+    int block = map[idx];
+    USB_TEST_ASSERT(block >= 1);
+    for(int i =0; i < block; i++) {
+        map[idx + i] = 0;
+    }
+}
+
+#endif // DBG_USE_POSIX_MEMALIGN
+
+void print_td(FILE* stream, HCTD* td)
+{
+    if (td == NULL) {
+        fprintf(stream, "TD %p:\n", td);
+        return;
+    }
+    uint32_t* p = reinterpret_cast<uint32_t*>(td);
+    fprintf(stream, "TD %p: %08X %08X %08X %08X", p, p[0], p[1], p[2], p[3]);
+    fprintf(stream, " ep=%p\n", td->parent);
+    uint8_t* bp = reinterpret_cast<uint8_t*>(p[1]);
+    uint8_t* be = reinterpret_cast<uint8_t*>(p[3]);
+    if (bp) {
+        fprintf(stream, "BF %p:", bp);
+        while(bp <= be) {
+            fprintf(stream, " %02X", *bp);
+            bp++;
+        }
+        fprintf(stream, "\n");
+    } 
+}
+
+void print_ed(FILE* stream, HCED* ed)
+{
+    uint32_t* p = reinterpret_cast<uint32_t*>(ed);
+    while(p) {
+        fprintf(stream, "ED %p: %08X %08X %08X %08X\n", p, p[0], p[1], p[2], p[3]);
+        HCTD* td = reinterpret_cast<HCTD*>(p[2] & ~3);
+        HCTD* tdtail = reinterpret_cast<HCTD*>(p[1]);
+        while(td != NULL && td != tdtail) {
+            print_td(stream, td);
+            td = td->Next;
+        }
+        p = reinterpret_cast<uint32_t*>(p[3]);
+    }
+}
+
+void print_itd(FILE* stream, HCITD* itd)
+{
+    if (itd == NULL) {
+        fprintf(stream, "ITD %p:\n", itd);
+        return;
+    }
+    uint32_t* p = reinterpret_cast<uint32_t*>(itd);
+    fprintf(stream, "ITD %p: %08X %08X %08X %08X", p, p[0], p[1], p[2], p[3]);
+    fprintf(stream, " ep=%p\n", itd->parent);
+    uint16_t* offset = reinterpret_cast<uint16_t*>(p+4);
+    fprintf(stream, "ITD %p: %04X %04X %04X %04X %04X %04X %04X %04X\n", offset, 
+        offset[0], offset[1], offset[2], offset[3], offset[4], offset[5], offset[6], offset[7]);
+}
+
+void print_ied(FILE* stream, HCED* ed)
+{
+    uint32_t* p = reinterpret_cast<uint32_t*>(ed);
+    while(p) {
+        fprintf(stream, "ED %p: %08X %08X %08X %08X\n", p, p[0], p[1], p[2], p[3]);
+        HCITD* itd = reinterpret_cast<HCITD*>(p[2] & ~3);
+        HCITD* itdtail = reinterpret_cast<HCITD*>(p[1]);
+        while(itd != NULL && itd != itdtail) {
+            print_itd(stream, itd);
+            itd = itd->Next;
+        }
+        p = reinterpret_cast<uint32_t*>(p[3]);
+    }
+}
+
+void print_bytes(FILE* stream, char* s, uint8_t* buf, int len)
+{
+    fprintf(stream, "%s %d:", s, len);
+    for(int i = 0; i < len; i++) {
+        fprintf(stream, " %02X", buf[i]);
+    }
+    fprintf(stream, "\n");
+}
+
+void print_hex(FILE* stream, uint8_t* p, int len)
+{
+    for(int i = 0; i < len; i++) {
+        if (i%16 == 0) {
+            fprintf(stream, "%p:", p);
+        }
+        fprintf(stream, " %02X", *p);
+        p++;
+        if (i%16 == 15) {
+            fprintf(stream, "\n");
+        }
+    }
+    fprintf(stream, "\n");
+}
+
+void assert_print(const char* pf, int line, const char* msg) {
+    printf("\n\n%s@%d %s ASSERT!\n\n", pf, line, msg);
+    exit(1);
+}
+
+#endif // defined(TARGET_LPC4088)||defined(TARGET_LPC1768)
+
+
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/USBHALHost_F401RE.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHost/USBHALHost_F401RE.cpp	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,539 @@
+#if defined(TARGET_NUCLEO_F401RE)||defined(TARGET_NUCLEO_F411RE)||defined(TARGET_NUCLEO_F446RE)||defined(TARGET_ARCH_MAX)
+#include "USBHALHost.h"
+#include <algorithm>
+
+#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)
+
+#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)
+{
+    HAL_Delay(t);
+}
+
+// usbh_conf.c
+extern HCD_HandleTypeDef hhcd_USB_OTG_FS;
+
+void HAL_HCD_MspInit(HCD_HandleTypeDef* hhcd)
+{  
+  GPIO_InitTypeDef  GPIO_InitStruct;
+  
+  if(hhcd->Instance == USB_OTG_FS)
+  {
+    /* 
+     * Configure USB FS GPIOs
+     * PA11     ------> USB_OTG_FS_DM
+     * PA12     ------> USB_OTG_FS_DP 
+     */
+    __HAL_RCC_GPIOA_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); 
+    
+    /* Enable USB FS Clocks */ 
+    __HAL_RCC_USB_OTG_FS_CLK_ENABLE();
+    
+    /* Set USBFS Interrupt to the lowest priority */
+    HAL_NVIC_SetPriority(OTG_FS_IRQn, 5, 0);
+    
+    /* Enable USBFS Interrupt */
+    HAL_NVIC_EnableIRQ(OTG_FS_IRQn);
+  } 
+  
+}
+
+// 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() {
+    instHost = this;
+}
+
+void USBHALHost::init() {
+    hhcd_USB_OTG_FS.Instance = USB_OTG_FS;
+    hhcd_USB_OTG_FS.Init.Host_channels = 8;
+    hhcd_USB_OTG_FS.Init.speed = HCD_SPEED_FULL;
+    hhcd_USB_OTG_FS.Init.dma_enable = DISABLE;
+    hhcd_USB_OTG_FS.Init.phy_itface = HCD_PHY_EMBEDDED;
+    hhcd_USB_OTG_FS.Init.Sof_enable = DISABLE;
+    hhcd_USB_OTG_FS.Init.low_power_enable = ENABLE;
+    hhcd_USB_OTG_FS.Init.vbus_sensing_enable = DISABLE;
+    hhcd_USB_OTG_FS.Init.use_external_vbus = DISABLE;
+
+    HAL_HCD_Init(&hhcd_USB_OTG_FS);
+    HAL_HCD_Start(&hhcd_USB_OTG_FS);
+
+    bool lowSpeed = wait_attach();
+    delay_ms(200);
+    HAL_HCD_ResetPort(&hhcd_USB_OTG_FS);
+    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_OTG_FS) == USB_OTG_SPEED_LOW;
+}
+
+int USBHALHost::token_setup(USBEndpoint* ep, SETUP_PACKET* setup, uint16_t wLength) {
+    const uint8_t ep_addr = 0x00;
+    HC hc;
+    USBDeviceConnected* dev = ep->getDevice();
+    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);
+
+    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) {
+    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;
+    USBDeviceConnected* dev = ep->getDevice();
+    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);
+
+    hc.SubmitRequest(data, size);
+    while(hc.GetURBState() == URB_IDLE);
+
+    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;
+    USBDeviceConnected* dev = ep->getDevice();
+    hc.Init(
+        ep->getAddress(),
+        dev->getAddress(),
+        dev->getSpeed() ? HCD_SPEED_LOW : HCD_SPEED_FULL,
+        EP_TYPE_INTR, ep->getSize());
+
+    hc.SetToggle((ep->getData01() == DATA0) ? 0 : 1);
+
+    hc.SubmitRequest(data, size);
+    //while(hc.GetURBState() == URB_IDLE);
+    wait_ms(2);
+    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;
+    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 {
+        hc.SubmitRequest(data, size);
+        while(hc.GetURBState() == URB_IDLE);
+
+        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;
+                        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) {
+    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;
+    USBDeviceConnected* dev = ep->getDevice();
+    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 {
+        hc.SubmitRequest((uint8_t*)data, size);
+        while(hc.GetURBState() == URB_IDLE);
+
+        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;
+    USBDeviceConnected* dev = ep->getDevice();
+    hc.Init(
+        ep->getAddress(),
+        dev->getAddress(),
+        dev->getSpeed() ? HCD_SPEED_LOW : HCD_SPEED_FULL,
+        EP_TYPE_INTR, ep->getSize());
+
+    hc.SetToggle((ep->getData01() == DATA0) ? 0 : 1);
+
+    hc.SubmitRequest((uint8_t*)data, size);
+    while(hc.GetURBState() == URB_IDLE);
+    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;
+    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 {
+        hc.SubmitRequest((uint8_t*)data, size);
+        while(hc.GetURBState() == URB_IDLE);
+
+        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) {
+    HC* hc = ep->getHALData<HC*>();
+    if (hc == NULL) {
+        hc = new HC;
+        ep->setHALData<HC*>(hc);
+        USBDeviceConnected* dev = ep->getDevice();
+        hc->Init(
+            ep->getAddress(), dev->getAddress(),
+            HCD_SPEED_FULL, EP_TYPE_ISOC, ep->getSize());
+    }
+    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) {
+    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);
+}
+
+uint8_t HC::slot = 0x00;
+
+HC::HC() {
+    static const int start = 1;
+    uint8_t mask = (1<<start);
+    for(int i = start; 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
+
+
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/USBHALHost_F401RE.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHost/USBHALHost_F401RE.h	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,58 @@
+#pragma once
+#include "mbed.h"
+#include "USBHostTypes.h"
+#include "USBEndpoint.h"
+
+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;
+    uint8_t prev_LastStatus;
+
+protected:
+    USBHALHost();
+    void init();
+    virtual bool addDevice(USBDeviceConnected* parent, int port, bool lowSpeed) = 0;
+    int token_setup(USBEndpoint* ep, SETUP_PACKET* setup, uint16_t wLength = 0);
+    int token_iso_in(USBEndpoint* ep, uint8_t* data, int size);
+    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);
+    void multi_token_inNB(USBEndpoint* ep, uint8_t* data, int size);
+    USB_TYPE multi_token_inNB_result(USBEndpoint* ep);
+    void setToggle(USBEndpoint* ep, uint8_t toggle);
+
+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_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);
+    int token_ctl_out(USBEndpoint* ep, const uint8_t* data, int size, int retryLimit);
+    int token_int_out(USBEndpoint* ep, const uint8_t* data, int size);
+    int token_blk_out(USBEndpoint* ep, const uint8_t* data, int size, int retryLimit);
+    bool wait_attach();
+    static USBHALHost * instHost;
+};
+
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/USBHALHost_KL46Z.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHost/USBHALHost_KL46Z.cpp	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,520 @@
+// Simple USBHost for FRDM-KL46Z
+#if defined(TARGET_KL46Z)||defined(TARGET_KL25Z)||defined(TARGET_K64F)
+#include "USBHALHost.h"
+#include <algorithm>
+
+#ifdef _USB_DBG
+#define USB_DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");} while(0);
+#define USB_DBG_HEX(A,B) debug_hex(A,B)
+void debug_hex(uint8_t* buf, int size);
+#else
+#define USB_DBG(...) while(0)
+#define USB_DBG_HEX(A,B) while(0)
+#endif
+
+#undef USB_TEST_ASSERT
+extern 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);
+
+#define BD_OWN_MASK        (1<<7)
+#define BD_DATA01_MASK     (1<<6)
+#define BD_KEEP_MASK       (1<<5)
+#define BD_NINC_MASK       (1<<4)
+#define BD_DTS_MASK        (1<<3)
+#define BD_STALL_MASK      (1<<2)
+
+#define TX    1
+#define RX    0
+
+#define EP0_BDT_IDX(dir, odd) (((2 * dir) + (1 * odd)))
+
+#define SETUP_TOKEN    0x0D
+#define IN_TOKEN       0x09
+#define OUT_TOKEN      0x01
+
+// for each endpt: 8 bytes
+struct BDT {
+    uint8_t   info;       // BD[0:7]
+    uint8_t   dummy;      // RSVD: BD[8:15]
+    uint16_t  byte_count; // BD[16:32]
+    uint32_t  address;    // Addr
+    void setBuffer(uint8_t* buf, int size) {
+        address = (uint32_t)buf;
+        byte_count = size;
+    }
+    uint8_t getStatus() {
+        return (info>>2)&0x0f;
+    }    
+};
+
+__attribute__((__aligned__(512))) BDT bdt[64];
+
+USBHALHost* USBHALHost::instHost;
+
+USBHALHost::USBHALHost() {
+    instHost = this;
+    report.clear();
+}
+
+void USBHALHost::init() {
+    // 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);
+
+    // enable OTG clock
+    SIM->SCGC4 |= SIM_SCGC4_USBOTG_MASK;
+
+    // USB Module Configuration
+    // Reset USB Module
+    USB0->USBTRC0 |= USB_USBTRC0_USBRESET_MASK;
+    while(USB0->USBTRC0 & USB_USBTRC0_USBRESET_MASK);
+
+    // Clear interrupt flag
+    USB0->ISTAT = 0xff;
+
+    // Set BDT Base Register
+    USB0->BDTPAGE1=(uint8_t)((uint32_t)bdt>>8);
+    USB0->BDTPAGE2=(uint8_t)((uint32_t)bdt>>16);
+    USB0->BDTPAGE3=(uint8_t)((uint32_t)bdt>>24);
+
+    // Set SOF threshold
+    USB0->SOFTHLD = USB_SOFTHLD_CNT(1);
+
+    // pulldown D+ and D-
+    USB0->USBCTRL = USB_USBCTRL_PDE_MASK;
+
+    USB0->USBTRC0 |= 0x40;
+
+    // Host mode
+    USB0->CTL |= USB_CTL_HOSTMODEEN_MASK;
+    // Desable SOF packet generation
+    USB0->CTL &= ~USB_CTL_USBENSOFEN_MASK;
+
+    NVIC_SetVector(USB0_IRQn, (uint32_t)_usbisr);
+    NVIC_EnableIRQ(USB0_IRQn);
+
+    bool lowSpeed = wait_attach();
+
+    for(int retry = 2; retry > 0; retry--) {
+        // Enable RESET
+        USB0->CTL |= USB_CTL_RESET_MASK;
+        wait_ms(500);
+        USB0->CTL &= ~USB_CTL_RESET_MASK;
+    
+        // Enable SOF
+        USB0->CTL |= USB_CTL_USBENSOFEN_MASK;
+        wait_ms(100);
+
+        // token transfer initialize
+        token_transfer_init();
+
+        USB0->INTEN |= USB_INTEN_TOKDNEEN_MASK|
+                       USB_INTEN_ERROREN_MASK;
+        USB0->ERREN |= USB_ERREN_PIDERREN_MASK|
+                       USB_ERREN_CRC5EOFEN_MASK|
+                       USB_ERREN_CRC16EN_MASK|
+                       USB_ERREN_DFN8EN_MASK|
+                       USB_ERREN_BTOERREN_MASK|
+                       USB_ERREN_DMAERREN_MASK|
+                       USB_ERREN_BTSERREN_MASK;
+
+        if (addDevice(NULL, 0, lowSpeed)) {
+            break;
+        }
+        USB_DBG("retry=%d", retry);
+        USB_TEST_ASSERT(retry > 1);
+    }
+}
+
+bool USBHALHost::wait_attach() {
+    attach_done = false;
+    USB0->INTEN = USB_INTEN_ATTACHEN_MASK;
+    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);
+    USB_TEST_ASSERT(!(USB0->CTL & USB_CTL_SE0_MASK));
+    root_lowSpeed = (USB0->CTL & USB_CTL_JSTATE_MASK) ? false : true;
+    return root_lowSpeed;
+}
+
+void USBHALHost::setAddr(int _addr, bool _lowSpeed) {
+    USB0->ADDR = (_lowSpeed ? USB_ADDR_LSEN_MASK : 0x00) | USB_ADDR_ADDR(_addr);
+}
+
+void USBHALHost::setEndpoint() {
+    USB0->ENDPOINT[0].ENDPT = (root_lowSpeed ? USB_ENDPT_HOSTWOHUB_MASK : 0x00)|
+                              USB_ENDPT_RETRYDIS_MASK|
+                              USB_ENDPT_EPCTLDIS_MASK|
+                              USB_ENDPT_EPRXEN_MASK|
+                              USB_ENDPT_EPTXEN_MASK|
+                              USB_ENDPT_EPHSHK_MASK;
+}
+
+void USBHALHost::token_transfer_init() {
+    tx_ptr = ODD;
+    rx_ptr = ODD;
+}
+
+int USBHALHost::token_setup(USBEndpoint* ep, SETUP_PACKET* setup, uint16_t wLength) {
+    USBDeviceConnected* dev = ep->getDevice();
+    setAddr(dev->getAddress(), dev->getSpeed());
+
+    for(int retry = 0;; retry++) {
+        token_ready();
+        USB0->ENDPOINT[0].ENDPT = (root_lowSpeed ? USB_ENDPT_HOSTWOHUB_MASK : 0x00) |
+                                  USB_ENDPT_RETRYDIS_MASK|
+                                  USB_ENDPT_EPRXEN_MASK|
+                                  USB_ENDPT_EPTXEN_MASK|
+                                  USB_ENDPT_EPHSHK_MASK;
+        CTASSERT(sizeof(SETUP_PACKET) == 8);
+        setup->wLength = wLength;
+        int idx = EP0_BDT_IDX(TX, tx_ptr);
+        bdt[idx].setBuffer((uint8_t*)setup, sizeof(SETUP_PACKET));
+        bdt[idx].info = BD_OWN_MASK |
+                        BD_DTS_MASK; // always data0
+        token_done = false;
+        USB0->TOKEN = USB_TOKEN_TOKENPID(SETUP_TOKEN)|
+                      USB_TOKEN_TOKENENDPT(ep->getAddress() & 0x7f);
+        while(!token_done);
+        LastStatus = bdt[idx].getStatus();
+        if (LastStatus == ACK) {
+            if (retry > 0) {
+                USB_DBG("retry=%d %02x", retry, prev_LastStatus);
+            }
+            break;
+        } else if (LastStatus == STALL) {
+            report.stall++;
+            return STALL;
+        }
+        if (retry > 10) {
+            USB_DBG("retry=%d", retry);
+            break;
+        }
+        prev_LastStatus = LastStatus;
+        wait_ms(100 * retry);
+    }
+    ep->setData01(DATA1); // next toggle
+    return LastStatus;
+}
+
+int USBHALHost::token_in(USBEndpoint* ep, uint8_t* data, int size, int retryLimit) {
+    USBDeviceConnected* dev = ep->getDevice();
+    setAddr(dev->getAddress(), dev->getSpeed());
+    setEndpoint();
+
+    for(int retry = 0;; retry++) {
+        token_ready();
+        int idx = EP0_BDT_IDX(RX, rx_ptr);
+        bdt[idx].setBuffer(data, size);
+        bdt[idx].info = BD_OWN_MASK|
+                        BD_DTS_MASK|
+                        (ep->getData01() == DATA1 ? BD_DATA01_MASK : 0);
+        token_done = false;
+        USB0->TOKEN = USB_TOKEN_TOKENPID(IN_TOKEN)|
+                      USB_TOKEN_TOKENENDPT(ep->getAddress()&0x7f);
+        while(!token_done);
+        LastStatus = bdt[idx].getStatus();
+        int len = bdt[idx].byte_count;
+        if (LastStatus == DATA0 || LastStatus == DATA1) {
+            USB_TEST_ASSERT(ep->getData01() == LastStatus);
+            ep->setData01(LastStatus == DATA0 ? DATA1 : DATA0);
+            if (retry > 0) {
+                //USB_DBG("len=%d retry=%d %02x", len, retry, prev_LastStatus);
+            }
+            return len;
+        } else if (LastStatus == STALL) {
+            report.stall++;
+            return -1;
+        } else if (LastStatus == NAK) {
+            report.nak++;
+            if (retry >= retryLimit) {
+                if (retryLimit > 0) {
+                    USB_DBG("retry=%d retryLimit=%d", retry, retryLimit);
+                }
+                return -1;
+            }
+            wait_ms(100 * retry);
+        } else if (LastStatus == Bus_Timeout) {
+            if (retry >= retryLimit) {
+                if (retryLimit > 0) {
+                    USB_DBG("Bus_Timeout retry=%d retryLimit=%d", retry, retryLimit);
+                }                
+                return -1;
+            }
+            wait_ms(500 + 100 * retry);
+        } else {
+            return -1;
+        }
+        prev_LastStatus = LastStatus;
+    }
+}
+
+int USBHALHost::token_out(USBEndpoint* ep, const uint8_t* data, int size, int retryLimit) {
+    USBDeviceConnected* dev = ep->getDevice();
+    USB_TEST_ASSERT(dev);
+    setAddr(dev->getAddress(), dev->getSpeed());
+    setEndpoint();
+
+    for(int retry = 0;; retry++) {
+        token_ready();
+        int idx = EP0_BDT_IDX(TX, tx_ptr);
+        bdt[idx].setBuffer((uint8_t*)data, size);
+        bdt[idx].info = BD_OWN_MASK|
+                        BD_DTS_MASK|
+                       (ep->getData01() == DATA1 ? BD_DATA01_MASK : 0);
+        token_done = false;
+        USB0->TOKEN = USB_TOKEN_TOKENPID(OUT_TOKEN)|
+                      USB_TOKEN_TOKENENDPT(ep->getAddress()&0x7f);
+        while(!token_done);
+        LastStatus = bdt[idx].getStatus();
+        int len = bdt[idx].byte_count;
+        //USB_DBG("len=%d %02x", len, LastStatus);
+        if (LastStatus == ACK) {
+            ep->toggleData01();
+            if (retry > 0) {
+                USB_DBG("len=%d retry=%d %02x", len, retry, prev_LastStatus);
+            }
+            return len;
+        } else if (LastStatus == STALL) {
+            report.stall++;
+            return -1;
+        } else if (LastStatus == NAK) {
+            report.nak++;
+            if (retry > retryLimit) {
+                USB_DBG("retry=%d retryLimit=%d", retry, retryLimit);
+                return -1;
+            }
+            wait_ms(100 * retry);
+        } else {
+            return -1;
+        }
+        prev_LastStatus = LastStatus;
+    }
+}
+
+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::token_iso_in(USBEndpoint* ep, uint8_t* data, int size) {
+    USBDeviceConnected* dev = ep->getDevice();
+    USB_TEST_ASSERT(dev);
+    setAddr(dev->getAddress());
+
+    while(USB0->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK); // TOKEN_BUSY ?
+    USB0->ISTAT |= USB_ISTAT_SOFTOK_MASK; // Clear SOF
+    while (!(USB0->ISTAT & USB_ISTAT_SOFTOK_MASK));
+    USB0->SOFTHLD = 0; // this is needed as without this you can get errors
+    USB0->ISTAT |= USB_ISTAT_SOFTOK_MASK; // clear SOF
+
+    USB0->ENDPOINT[0].ENDPT = USB_ENDPT_EPCTLDIS_MASK|
+                              USB_ENDPT_RETRYDIS_MASK|
+                              USB_ENDPT_EPRXEN_MASK|
+                              USB_ENDPT_EPTXEN_MASK;
+    int idx = EP0_BDT_IDX(RX, rx_ptr);
+    bdt[idx].setBuffer(data, size);
+    bdt[idx].info = BD_OWN_MASK|
+                    BD_DTS_MASK; // always DATA0
+    token_done = false;
+    USB0->TOKEN = USB_TOKEN_TOKENPID(IN_TOKEN)|
+                  USB_TOKEN_TOKENENDPT(ep->getAddress()&0x7f);
+    while(!token_done);
+    LastStatus = bdt[idx].getStatus();
+    int len = bdt[idx].byte_count;
+    if (LastStatus == DATA0) {
+        return len;
+    }
+    return -1;
+}
+
+void USBHALHost::token_ready() {
+    while(USB0->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK) { // TOKEN_BUSY ?
+        wait_ms(1);
+    }
+    USB0->ISTAT |= USB_ISTAT_SOFTOK_MASK; // Clear SOF
+    while (!(USB0->ISTAT & USB_ISTAT_SOFTOK_MASK));
+    USB0->SOFTHLD = 0; // this is needed as without this you can get errors
+    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) {
+    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();
+    }
+}
+
+void USBHALHost::UsbIrqhandler() {
+    if (USB0->ISTAT & USB_ISTAT_TOKDNE_MASK) {
+        uint8_t stat = USB0->STAT;
+        ODD_EVEN next_ptr = (stat & USB_STAT_ODD_MASK) ? ODD : EVEN;
+        if (stat & USB_STAT_TX_MASK) {
+            tx_ptr = next_ptr;
+        } else {
+            rx_ptr = next_ptr;
+        }
+        USB0->ISTAT = USB_ISTAT_TOKDNE_MASK;
+        token_done = true;
+    }
+    if (USB0->ISTAT & USB_ISTAT_ATTACH_MASK) {
+        USB0->INTEN &= ~USB_INTEN_ATTACHEN_MASK;
+        USB0->ISTAT = USB_ISTAT_ATTACH_MASK;
+        attach_done = true;
+    }
+    if (USB0->ISTAT & USB_ISTAT_ERROR_MASK) {
+        uint8_t errstat = USB0->ERRSTAT;
+        if (errstat & USB_ERRSTAT_PIDERR_MASK) {
+            report.errstat_piderr++;
+        }
+        if (errstat & USB_ERRSTAT_CRC5EOF_MASK) {
+            report.errstat_crc5eof++;
+        }
+        if (errstat & USB_ERRSTAT_CRC16_MASK) {
+            report.errstat_crc16++;
+        }
+        if (errstat & USB_ERRSTAT_DFN8_MASK) {
+            report.errstat_dfn8++;
+        }
+        if (errstat & USB_ERRSTAT_BTOERR_MASK) {
+            report.errstat_btoerr++;
+        }
+        if (errstat & USB_ERRSTAT_DMAERR_MASK) {
+            report.errstat_dmaerr++;
+        }
+        if (errstat & USB_ERRSTAT_BTSERR_MASK) {
+            report.errstat_btoerr++;
+        }
+        USB0->ERRSTAT = errstat;
+        USB0->ISTAT = USB_ISTAT_ERROR_MASK;
+    }
+}
+
+void Report::clear() {
+    errstat_piderr = 0;
+    errstat_crc5eof = 0;
+    errstat_crc16 = 0;
+    errstat_dfn8 = 0;
+    errstat_btoerr = 0;
+    errstat_dmaerr = 0;
+    errstat_bsterr = 0;
+    //
+    nak = 0;
+}
+
+void Report::print_errstat() {
+    printf("ERRSTAT PID: %d, CRC5EOF: %d, CRC16: %d, DFN8: %d, BTO: %d, DMA: %d, BST: %d\n",
+        errstat_piderr, errstat_crc5eof,
+        errstat_crc16, errstat_dfn8,
+        errstat_btoerr, errstat_dmaerr, errstat_bsterr);
+}
+
+void debug_hex(uint8_t* buf, int size) {
+    int n = 0;
+    for(int i = 0; i < size; i++) {
+        fprintf(stderr, "%02x ", buf[i]);
+        if (++n >= 16) {
+            fprintf(stderr, "\n");
+            n = 0;
+        }
+    }
+    if (n > 0) {
+        fprintf(stderr, "\n");
+    }
+}
+
+#endif
+
+
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/USBHALHost_KL46Z.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHost/USBHALHost_KL46Z.h	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,68 @@
+#pragma once
+#include "mbed.h"
+#include "USBHostTypes.h"
+#include "USBEndpoint.h"
+
+#define GET_CONFIGURATION 8
+
+// TOK_PID[5:2]
+#define Bus_Timeout 0x00
+#define Data_Error 0x0f
+
+enum ODD_EVEN {
+    ODD = 0,
+    EVEN = 1,
+};
+
+class Report {
+public:
+    void clear();
+    void print_errstat();
+    // error count
+    uint32_t errstat_piderr; // USBx_ERRSTAT[PIDERR]
+    uint32_t errstat_crc5eof;// USBx_ERRSTAT[CRC5EOF]
+    uint32_t errstat_crc16;  // USBx_ERRSTAT[CRC16]
+    uint32_t errstat_dfn8;   // USBx_ERRSTAT[DFN8]
+    uint32_t errstat_btoerr; // USBx_ERRSTAT[BTOERR]
+    uint32_t errstat_dmaerr; // USBx_ERRSTAT[DMAERR]
+    uint32_t errstat_bsterr; // USBx_ERRSTAT[BTSERR]
+    //
+    uint32_t nak;
+    uint32_t stall;
+};
+
+class USBHALHost {
+public:
+    uint8_t LastStatus;
+    uint8_t prev_LastStatus;
+    Report report;
+
+protected:
+    USBHALHost();
+    void init();
+    virtual bool addDevice(USBDeviceConnected* parent, int port, bool lowSpeed) = 0;
+    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);
+    void multi_token_inNB(USBEndpoint* ep, uint8_t* data, int size);
+    USB_TYPE multi_token_inNB_result(USBEndpoint* ep);
+    void setToggle(USBEndpoint* ep, uint8_t toggle);
+    int token_iso_in(USBEndpoint* ep, uint8_t* data, int size);
+
+private:
+    void setAddr(int addr, bool lowSpeed = false);
+    void setEndpoint();
+    void token_transfer_init();
+    void token_ready();
+    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);
+    static void _usbisr(void);
+    void UsbIrqhandler();
+    __IO bool attach_done;
+    __IO bool token_done;
+    bool wait_attach();
+    bool root_lowSpeed;
+    ODD_EVEN tx_ptr;
+    ODD_EVEN rx_ptr;
+    static USBHALHost * instHost;
+};
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/USBHALHost_LPC4088.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHost/USBHALHost_LPC4088.cpp	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,604 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if defined(TARGET_LPC4088)||defined(TARGET_LPC1768)
+#include "USBHALHost.h"
+
+#ifndef CTASSERT
+template <bool>struct CtAssert;
+template <>struct CtAssert<true> {};
+#define CTASSERT(A) CtAssert<A>();
+#endif
+
+#ifdef _USB_DBG
+#define USB_DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");} while(0);
+#define USB_DBG_HEX(A,B) debug_hex(A,B)
+#define USB_DBG_ED(A) while(0)
+#define USB_DBG_TD(A) while(0)
+#define USB_DBG_ED_IF(A,B) while(0)
+void debug_hex(uint8_t* buf, int size);
+#else
+#define USB_DBG(...) while(0)
+#define USB_DBG_ED(A) while(0)
+#define USB_DBG_TD(A) while(0)
+#define USB_DBG_ED_IF(A,B) while(0)
+#define USB_DBG_HEX(A,B) while(0)
+#endif
+
+#define USB_TRACE1(A) while(0)
+
+#ifdef _USB_TEST
+#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__);}
+#else
+#define USB_TEST_ASSERT(EXPR) while(0)
+#endif
+
+#define USB_INFO(...) do{fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");}while(0);
+
+// bits of the USB/OTG clock control register
+#define HOST_CLK_EN     (1<<0)
+#define DEV_CLK_EN      (1<<1)
+#define PORTSEL_CLK_EN  (1<<3)
+#define AHB_CLK_EN      (1<<4)
+
+// bits of the USB/OTG clock status register
+#define HOST_CLK_ON     (1<<0)
+#define DEV_CLK_ON      (1<<1)
+#define PORTSEL_CLK_ON  (1<<3)
+#define AHB_CLK_ON      (1<<4)
+
+// we need host clock, OTG/portsel clock and AHB clock
+#define CLOCK_MASK (HOST_CLK_EN | PORTSEL_CLK_EN | AHB_CLK_EN)
+#define  FI                     0x2EDF           /* 12000 bits per frame (-1) */
+#define  DEFAULT_FMINTERVAL     ((((6 * (FI - 210)) / 7) << 16) | FI)
+
+USBHALHost* USBHALHost::instHost;
+
+USBHALHost::USBHALHost() {
+    instHost = this;
+}
+
+void USBHALHost::init() {
+    NVIC_DisableIRQ(USB_IRQn);
+    m_pHcca = new HCCA();
+    init_hw_ohci(m_pHcca);
+    ResetRootHub();
+    NVIC_SetVector(USB_IRQn, (uint32_t)_usbisr);
+    NVIC_SetPriority(USB_IRQn, 0);
+    NVIC_EnableIRQ(USB_IRQn);
+
+    USB_INFO("Simple USBHost Library for LPC4088/LPC1768");
+    bool lowSpeed = wait_attach();
+    addDevice(NULL, 0, lowSpeed);
+}
+
+void USBHALHost::init_hw_ohci(HCCA* pHcca) {
+    LPC_SC->PCONP &= ~(1UL<<31);    //Cut power
+    wait_ms(1000);
+    LPC_SC->PCONP |= (1UL<<31);     // turn on power for USB
+    LPC_USB->USBClkCtrl |= CLOCK_MASK; // Enable USB host clock, port selection and AHB clock
+    // Wait for clocks to become available
+    while ((LPC_USB->USBClkSt & CLOCK_MASK) != CLOCK_MASK)
+        ;
+    LPC_USB->OTGStCtrl |= 1;
+    LPC_USB->USBClkCtrl &= ~PORTSEL_CLK_EN;
+    
+#if defined(TARGET_LPC1768)
+    LPC_PINCON->PINSEL1 &= ~((3<<26) | (3<<28));  
+    LPC_PINCON->PINSEL1 |=  ((1<<26)|(1<<28));     // 0x14000000
+#elif defined(TARGET_LPC4088)
+    LPC_IOCON->P0_29 = 0x01; // USB_D+1
+    LPC_IOCON->P0_30 = 0x01; // USB_D-1
+    // DO NOT CHANGE P1_19.
+#else
+#error "target error"
+#endif
+    USB_DBG("initialize OHCI\n");
+    wait_ms(100);                                   /* Wait 50 ms before apply reset              */
+    USB_TEST_ASSERT((LPC_USB->HcRevision&0xff) == 0x10); // check revision
+    LPC_USB->HcControl       = 0;                       /* HARDWARE RESET                             */
+    LPC_USB->HcControlHeadED = 0;                       /* Initialize Control list head to Zero       */
+    LPC_USB->HcBulkHeadED    = 0;                       /* Initialize Bulk list head to Zero          */
+                                                        /* SOFTWARE RESET                             */
+    LPC_USB->HcCommandStatus = OR_CMD_STATUS_HCR;
+    LPC_USB->HcFmInterval    = DEFAULT_FMINTERVAL;      /* Write Fm Interval and Largest Data Packet Counter */
+    LPC_USB->HcPeriodicStart = FI*90/100;
+                                                      /* Put HC in operational state                */
+    LPC_USB->HcControl  = (LPC_USB->HcControl & (~OR_CONTROL_HCFS)) | OR_CONTROL_HC_OPER;
+    LPC_USB->HcRhStatus = OR_RH_STATUS_LPSC;            /* Set Global Power */
+    USB_TEST_ASSERT(pHcca);
+    for (int i = 0; i < 32; i++) {
+        pHcca->InterruptTable[i] = NULL;
+    }
+    LPC_USB->HcHCCA = reinterpret_cast<uint32_t>(pHcca);
+    LPC_USB->HcInterruptStatus |= LPC_USB->HcInterruptStatus; /* Clear Interrrupt Status */
+    LPC_USB->HcInterruptEnable  = OR_INTR_ENABLE_MIE|OR_INTR_ENABLE_WDH|OR_INTR_ENABLE_FNO;
+
+    LPC_USB->HcRhPortStatus1 = OR_RH_PORT_CSC;
+    LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC;
+}
+
+void USBHALHost::ResetRootHub() {
+    wait_ms(100); /* USB 2.0 spec says at least 50ms delay before port reset */
+    LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRS; // Initiate port reset
+    USB_DBG("Before loop\n");
+    while (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_PRS)
+      ;
+    LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC; // ...and clear port reset signal
+    USB_DBG("After loop\n");
+    wait_ms(200); /* Wait for 100 MS after port reset  */
+}
+
+bool USBHALHost::wait_attach() {
+    bool lowSpeed = false;
+    uint32_t status = LPC_USB->HcRhPortStatus1;
+    if (status & OR_RH_PORT_LSDA) { // lowSpeedDeviceAttached
+        lowSpeed = true;
+    }
+    return lowSpeed;
+}
+
+void enable(ENDPOINT_TYPE type) {
+    switch(type) {
+        case CONTROL_ENDPOINT:
+            LPC_USB->HcCommandStatus |= OR_CMD_STATUS_CLF;
+            LPC_USB->HcControl |= OR_CONTROL_CLE;
+            break;
+        case ISOCHRONOUS_ENDPOINT:
+            LPC_USB->HcControl |= OR_CONTROL_PLE;
+            break;
+        case BULK_ENDPOINT:
+            LPC_USB->HcCommandStatus |= OR_CMD_STATUS_BLF;
+            LPC_USB->HcControl |= OR_CONTROL_BLE;
+            break;
+        case INTERRUPT_ENDPOINT:
+            LPC_USB->HcControl |= OR_CONTROL_PLE;
+            break;
+    }
+}
+
+void USBHALHost::token_init(USBEndpoint* ep) {
+    HCED* ed = ep->getHALData<HCED*>();
+    if (ed == NULL) {
+        ed = new HCED(ep);
+        ep->setHALData<HCED*>(ed);
+    }
+    USBDeviceConnected* dev = ep->getDevice();
+    USB_TEST_ASSERT(dev);
+    if (dev) {
+        uint8_t devAddr = dev->getAddress();
+        USB_DBG("devAddr=%02x", devAddr);
+        ed->setFunctionAddress(devAddr);
+    }
+    uint16_t size = ep->getSize();
+    USB_DBG("MaxPacketSize=%d", size);
+    ed->setMaxPacketSize(size);
+    if (ed->HeadTd == NULL) {
+        HCTD* td = new HCTD(ed);
+        ed->TailTd = td;
+        ed->HeadTd = td;
+        switch(ep->getType()) {
+            case CONTROL_ENDPOINT:
+                ed->Next = reinterpret_cast<HCED*>(LPC_USB->HcControlHeadED);
+                LPC_USB->HcControlHeadED = reinterpret_cast<uint32_t>(ed);
+                break;
+            case BULK_ENDPOINT:
+                ed->Next = reinterpret_cast<HCED*>(LPC_USB->HcBulkHeadED);
+                LPC_USB->HcBulkHeadED = reinterpret_cast<uint32_t>(ed);
+                break;
+            case INTERRUPT_ENDPOINT:
+                HCCA* pHcca = reinterpret_cast<HCCA*>(LPC_USB->HcHCCA);
+                ed->Next = pHcca->InterruptTable[0];
+                pHcca->InterruptTable[0] = ed;
+                break;
+        }
+    }
+}
+
+int USBHALHost::token_setup(USBEndpoint* ep, SETUP_PACKET* setup, uint16_t wLength) {
+    token_init(ep);
+    HCED* ed = ep->getHALData<HCED*>();
+    HCTD* td = ed->TailTd;
+    setup->wLength = wLength;
+    TBUF* tbuf = new(sizeof(SETUP_PACKET))TBUF(setup, sizeof(SETUP_PACKET));
+    td->transfer(tbuf, sizeof(SETUP_PACKET));
+    td->Control |= TD_TOGGLE_0|TD_SETUP; // DATA0
+    HCTD* blank = new HCTD(ed);
+    ed->enqueue(blank);
+    //DBG_ED(ed);
+    enable(ep->getType());
+
+    td = ed->get_queue_HCTD();
+    USB_TEST_ASSERT(td);
+    int result = td->getLengthTransferred();
+    USB_DBG_TD(td);
+    delete tbuf;
+    delete td;
+    return result;
+}
+
+static HCED* getHCED_iso(USBEndpoint* ep) {
+    HCED* ed = ep->getHALData<HCED*>();
+    if (ed != NULL) {
+        return ed;
+    }
+    ed = new HCED(ep);
+    ep->setHALData<HCED*>(ed);
+    ed->setFormat(); // F Format ITD
+    ed->iso.FrameCount = ep->ohci.frameCount;
+    ed->iso.queue_limit = ep->ohci.queueLimit;
+    ed->iso.queue_count = 0;
+    ed->iso.Current_FrameCount = 0;
+    ed->iso.Current_itd = NULL;
+    ed->iso.FrameNumber = LPC_USB->HcFmNumber + 10; // after 10msec
+    HCITD* itd = ed->new_HCITD();
+    ed->init_queue(reinterpret_cast<HCTD*>(itd)); 
+    HCCA* hcca = reinterpret_cast<HCCA*>(LPC_USB->HcHCCA);
+    hcca->enqueue(ed);
+    LPC_USB->HcControl |= OR_CONTROL_PLE; // PeriodicListEnable
+    LPC_USB->HcControl |= OR_CONTROL_IE;  // IsochronousEnable
+    return ed;
+}
+
+static void enablePeriodic() {
+    LPC_USB->HcControl |= OR_CONTROL_PLE;
+}
+
+HCITD* isochronousReceive(USBEndpoint* ep) {
+    HCED* ed = getHCED_iso(ep);
+    USB_TEST_ASSERT(ed);
+    while(ed->iso.queue_count < ed->iso.queue_limit) {
+        HCITD* blank_itd = ed->new_HCITD();
+        if (ed->enqueue(reinterpret_cast<HCTD*>(blank_itd))) {
+            ed->iso.queue_count++;
+        }
+        enablePeriodic();
+    }
+    
+    HCITD* itd = ed->get_queue_HCITD();
+    if (itd) {
+        ed->iso.queue_count--;
+    }
+    return itd;
+}
+
+int USBHALHost::token_iso_in(USBEndpoint* ep, uint8_t* data, int size) {
+    HCED* ed = getHCED_iso(ep);
+    if (ed->iso.Current_FrameCount == 0) {
+        HCITD* itd = isochronousReceive(ep);
+        if (itd == NULL) {
+            return -1;
+        }
+        if (itd->ConditionCode() != 0) {
+            delete itd;
+            return -1;
+        }
+        ed->iso.Current_itd = itd;
+    }
+
+    HCITD* itd = ed->iso.Current_itd;
+    int fc = ed->iso.Current_FrameCount;
+    int result = -1;
+    uint8_t cc = itd->ConditionCode(fc);
+    if (cc == 0 || cc == 9) {
+        result = itd->Length(fc);
+        memcpy(data, itd->Buffer(fc), result);
+    }
+
+    if (++ed->iso.Current_FrameCount >= itd->FrameCount()) {
+        ed->iso.Current_FrameCount = 0;
+        delete ed->iso.Current_itd;
+    }
+    return result;
+}
+
+int USBHALHost::multi_token_in(USBEndpoint* ep, uint8_t* data, int size) {
+    token_init(ep);
+    HCED* ed = ep->getHALData<HCED*>();
+    HCTD* td = ed->TailTd;
+    TBUF* tbuf = NULL;
+    if (data != NULL) {
+        tbuf = new(size)TBUF();
+        td->transfer(tbuf, size);
+    }
+    td->Control |= TD_IN;
+    HCTD* blank = new HCTD(ed);
+    ed->enqueue(blank);
+    USB_DBG_ED_IF(ed->EndpointNumber()==0, ed); // control transfer
+    enable(ep->getType());
+
+    td = ed->get_queue_HCTD();
+    USB_TEST_ASSERT(td);
+    if (data != NULL) {
+        memcpy(data, tbuf->buf, size);
+        delete tbuf;
+    }
+    int result = td->getLengthTransferred();
+    delete td;
+    return result;
+}
+
+int USBHALHost::multi_token_out(USBEndpoint* ep, const uint8_t* data, int size) {
+    token_init(ep);
+    HCED* ed = ep->getHALData<HCED*>();
+    HCTD* td = ed->TailTd;
+    TBUF* tbuf = NULL;
+    if (data != NULL) {
+        tbuf = new(size)TBUF(data, size);
+        td->transfer(tbuf, size);
+    }
+    td->Control |= TD_OUT;
+    HCTD* blank = new HCTD(ed);
+    ed->enqueue(blank);
+    USB_DBG_ED(ed);
+    enable(ep->getType());
+
+    td = ed->get_queue_HCTD();
+    USB_TEST_ASSERT(td);
+    if (data != NULL) {
+        delete tbuf;
+    }
+    int result = td->getLengthTransferred();
+    delete td;
+    return result;
+}
+
+void USBHALHost::multi_token_inNB(USBEndpoint* ep, uint8_t* data, int size) {
+    token_init(ep);
+    HCED* ed = ep->getHALData<HCED*>();
+    HCTD* td = ed->TailTd;
+    TBUF* tbuf = new(size)TBUF();
+    td->transfer(tbuf, size);
+    td->Control |= TD_IN;
+    HCTD* blank = new HCTD(ed);
+    ed->enqueue(blank);
+    enable(ep->getType());
+}
+
+USB_TYPE USBHALHost::multi_token_inNB_result(USBEndpoint* ep) {
+    HCED* ed = ep->getHALData<HCED*>();
+    if (ed == NULL) {
+        return USB_TYPE_ERROR;
+    }
+    HCTD* td = ed->get_queue_HCTD(0);
+    if (td) {
+        int len = td->getLengthTransferred();
+        TBUF* tbuf = (TBUF*)td->buf_top;
+        memcpy(ep->getBufStart(), tbuf->buf, len);
+        ep->setLengthTransferred(len);
+        ep->setState((USB_TYPE)td->ConditionCode());
+        delete td;
+        delete tbuf;
+        return USB_TYPE_OK;
+    }
+    return USB_TYPE_PROCESSING;
+}
+
+void USBHALHost::setToggle(USBEndpoint* ep, uint8_t toggle) {
+    USB_TEST_ASSERT(toggle == 1);
+    HCED* ed = ep->getHALData<HCED*>();
+    ed->setToggle(toggle);
+}
+
+void USBHALHost::_usbisr(void) {
+    if (instHost) {
+        instHost->UsbIrqhandler();
+    }
+}
+
+HCTD* td_reverse(HCTD* td)
+{
+    HCTD* result = NULL;
+    HCTD* next;
+    while(td) {
+        next = const_cast<HCTD*>(td->Next);
+        td->Next = result;
+        result = td;
+        td = next;
+    }
+    return result;
+}
+
+void USBHALHost::UsbIrqhandler() {
+    if (!(LPC_USB->HcInterruptStatus & LPC_USB->HcInterruptEnable)) {
+        return;
+    }
+    m_report_irq++;
+    uint32_t status = LPC_USB->HcInterruptStatus;
+    if (status & OR_INTR_STATUS_FNO) {
+        m_report_FNO++;
+    }
+    if (status & OR_INTR_STATUS_WDH) {
+        union {
+            HCTD* done_td;
+            uint32_t lsb;
+        };
+        done_td = const_cast<HCTD*>(m_pHcca->DoneHead);
+        USB_TEST_ASSERT(done_td);
+        m_pHcca->DoneHead = NULL; // reset
+        if (lsb & 1) { // error ?
+            lsb &= ~1;
+        }
+        HCTD* td = td_reverse(done_td);
+        while(td) {
+            HCED* ed = td->parent;
+            USB_TEST_ASSERT(ed);
+            if (ed) {
+                ed->irqWdhHandler(td);
+            }
+            td = td->Next;
+        }
+        m_report_WDH++;
+    }
+    LPC_USB->HcInterruptStatus = status; // Clear Interrrupt Status
+}
+
+TBUF::TBUF(const void* data, int size) {
+    if (size > 0) {
+        memcpy(buf, data, size);
+    }
+}
+
+HCTD::HCTD(HCED* obj) {
+    CTASSERT(sizeof(HCTD) == 36);
+    USB_TEST_ASSERT(obj);
+    Control = TD_CC|TD_ROUNDING;
+    CurrBufPtr = NULL;
+    Next = NULL;
+    BufEnd = NULL;
+    buf_top = NULL;
+    buf_size = 0;
+    parent = obj;
+}
+
+HCITD::HCITD(HCED* obj, uint16_t FrameNumber, int FrameCount, uint16_t PacketSize) {
+    Control = 0xe0000000           | // CC ConditionCode NOT ACCESSED
+             ((FrameCount-1) << 24)| // FC FrameCount
+                  TD_DELAY_INT(0)  | // DI DelayInterrupt
+                 FrameNumber;        // SF StartingFrame
+    BufferPage0 = const_cast<uint8_t*>(buf);
+    BufferEnd = const_cast<uint8_t*>(buf) + PacketSize * FrameCount - 1;
+    Next = NULL; 
+    parent = obj;
+    uint32_t addr = reinterpret_cast<uint32_t>(buf);
+    for(int i = 0; i < FrameCount; i++) {
+        uint16_t offset = addr & 0x0fff;
+        if ((addr&0xfffff000) == (reinterpret_cast<uint32_t>(BufferEnd)&0xfffff000)) {
+            offset |= 0x1000;
+        }
+        OffsetPSW[i] = 0xe000|offset;
+        addr += PacketSize;
+    }
+}
+
+uint8_t* HCITD::Buffer(int fc) {
+    int offset = fc * parent->getMaxPacketSize();
+    return const_cast<uint8_t*>(buf) + offset;
+}
+
+HCED::HCED(USBEndpoint* ep) {
+    CTASSERT(sizeof(HCED) <= (64*2));
+    USBDeviceConnected* dev = ep->getDevice();
+    int devAddr = 0;
+    bool lowSpeed = false;
+    if (dev) {
+        devAddr = dev->getAddress();
+        lowSpeed = dev->getSpeed();
+    }
+    int ep_number = ep->getAddress();
+    int MaxPacketSize = ep->getSize();
+        Control =  devAddr        | /* USB address */
+        ((ep_number & 0x7F) << 7) | /* Endpoint address */
+        (ep_number!=0?(((ep_number&0x80)?2:1) << 11):0)| /* direction : Out = 1, 2 = In */
+        ((lowSpeed?1:0) << 13)    | /* speed full=0 low=1 */
+        (MaxPacketSize << 16);      /* MaxPkt Size */
+        TailTd = NULL;
+        HeadTd = NULL;
+        Next = NULL;
+}
+
+bool HCED::enqueue(HCTD* td) {
+    if (td) {
+        HCTD* tail = reinterpret_cast<HCTD*>(TailTd);
+        if (tail) {
+            tail->Next = td;
+            TailTd = reinterpret_cast<HCTD*>(td);
+            return true;
+        }
+    }
+    return false;
+}
+
+void HCED::init_queue(HCTD* td) {
+    TailTd = reinterpret_cast<HCTD*>(td);
+    HeadTd = reinterpret_cast<HCTD*>(td); 
+}
+
+void HCED::setToggle(uint8_t toggle) {
+    uint32_t c = reinterpret_cast<uint32_t>(HeadTd);
+    if (toggle == 0) { // DATA0
+        c &= ~0x02;
+    } else { // DATA1
+        c |= 0x02;
+    }
+    HeadTd = reinterpret_cast<HCTD*>(c);
+}
+
+uint8_t HCED::getToggle() {
+    uint32_t c = reinterpret_cast<uint32_t>(HeadTd);
+    return (c&0x02) ? 1 : 0;
+}
+
+HCTD* HCED::get_queue_HCTD(uint32_t millisec)
+{
+    for(int i = 0; i < 16; i++) {
+        osEvent evt = done_queue_get(millisec);
+        if (evt.status == osEventMessage) {
+            HCTD* td = reinterpret_cast<HCTD*>(evt.value.p);
+            USB_TEST_ASSERT(td);
+            uint8_t cc = td->ConditionCode();
+            if (cc != 0) {
+                m_ConditionCode = cc;
+                USB_DBG_TD(td);
+            }
+            return td;
+        } else if (evt.status == osOK) {
+            continue;
+        } else if (evt.status == osEventTimeout) {
+            return NULL;
+        } else {
+            USB_DBG("evt.status: %02x\n", evt.status);
+            USB_TEST_ASSERT(evt.status == osEventMessage);
+        }
+    }
+    return NULL;
+}
+
+HCITD* HCED::get_queue_HCITD() {
+    osEvent evt = done_queue_get(0);
+    if (evt.status == osEventMessage) {
+        HCITD* itd = reinterpret_cast<HCITD*>(evt.value.p);
+        USB_TEST_ASSERT(itd);
+        return itd;
+    }
+    return NULL;
+}
+HCITD* HCED::new_HCITD() {
+    uint16_t mps = getMaxPacketSize();
+    int total_size = mps * iso.FrameCount;
+    HCITD* itd = new(total_size)HCITD(this, iso.FrameNumber, iso.FrameCount, mps);
+    iso.FrameNumber += iso.FrameCount;
+    return itd;
+}
+
+void HCCA::enqueue(HCED* ed) {
+    for(int i = 0; i < 32; i++) {
+        if (InterruptTable[i] == NULL) {
+            InterruptTable[i] = ed;
+        } else {
+            HCED* nextEd = InterruptTable[i];
+            while(nextEd->Next && nextEd->Next != ed) {
+                nextEd = nextEd->Next;
+            }
+            nextEd->Next = ed;
+        }
+    }
+}
+
+#endif // defined(TARGET_LPC4088)||defined(TARGET_LPC1768)
+
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/USBHALHost_LPC4088.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHost/USBHALHost_LPC4088.h	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,284 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+#pragma once
+#include "mbed.h"
+#include "rtos.h"
+#include "USBHostTypes.h"
+#include "USBEndpoint.h"
+
+#if defined(TARGET_LPC4088)
+#define HcRevision      Revision
+#define HcControl       Control
+#define HcCommandStatus CommandStatus
+#define HcInterruptStatus InterruptStatus
+#define HcInterruptEnable InterruptEnable
+#define HcHCCA          HCCA
+#define HcControlHeadED ControlHeadED
+#define HcBulkHeadED    BulkHeadED
+#define HcFmInterval    FmInterval
+#define HcFmNumber      FmNumber
+#define HcPeriodicStart PeriodicStart
+#define HcRhStatus      RhStatus
+#define HcRhPortStatus1 RhPortStatus1
+#define OTGStCtrl       StCtrl
+#endif
+// ------------------ HcControl Register ---------------------
+#define  OR_CONTROL_PLE                 0x00000004
+#define  OR_CONTROL_IE                  0x00000008
+#define  OR_CONTROL_CLE                 0x00000010
+#define  OR_CONTROL_BLE                 0x00000020
+#define  OR_CONTROL_HCFS                0x000000C0
+#define  OR_CONTROL_HC_OPER             0x00000080
+// ----------------- HcCommandStatus Register -----------------
+#define  OR_CMD_STATUS_HCR              0x00000001
+#define  OR_CMD_STATUS_CLF              0x00000002
+#define  OR_CMD_STATUS_BLF              0x00000004
+// --------------- HcInterruptStatus Register -----------------
+#define  OR_INTR_STATUS_WDH             0x00000002
+#define  OR_INTR_STATUS_UE              0x00000010
+#define  OR_INTR_STATUS_FNO             0x00000020
+#define  OR_INTR_STATUS_RHSC            0x00000040
+// --------------- HcInterruptEnable Register -----------------
+#define  OR_INTR_ENABLE_WDH             0x00000002
+#define  OR_INTR_ENABLE_FNO             0x00000020
+#define  OR_INTR_ENABLE_RHSC            0x00000040
+#define  OR_INTR_ENABLE_MIE             0x80000000
+// ---------------- HcRhDescriptorA Register ------------------
+#define  OR_RH_STATUS_LPSC              0x00010000
+#define  OR_RH_STATUS_DRWE              0x00008000
+// -------------- HcRhPortStatus[1:NDP] Register --------------
+#define  OR_RH_PORT_CCS                 0x00000001
+#define  OR_RH_PORT_PRS                 0x00000010
+#define  OR_RH_PORT_LSDA                0x00000200
+#define  OR_RH_PORT_CSC                 0x00010000
+#define  OR_RH_PORT_PRSC                0x00100000
+
+// TRANSFER DESCRIPTOR CONTROL FIELDS
+#define  TD_ROUNDING     (uint32_t)(0x00040000) /* Buffer Rounding */
+#define  TD_SETUP        (uint32_t)(0x00000000) /* Direction of Setup Packet */
+#define  TD_IN           (uint32_t)(0x00100000) /* Direction In */
+#define  TD_OUT          (uint32_t)(0x00080000) /* Direction Out */
+#define  TD_DELAY_INT(x) (uint32_t)((x) << 21)  /* Delay Interrupt */
+#define  TD_DI           (uint32_t)(7<<21)      /* desable interrupt */
+#define  TD_TOGGLE_0     (uint32_t)(0x02000000) /* Toggle 0 */
+#define  TD_TOGGLE_1     (uint32_t)(0x03000000) /* Toggle 1 */
+#define  TD_CC           (uint32_t)(0xF0000000) /* Completion Code */
+
+void* usb_ram_malloc(size_t size, int aligment); // USBHALHost2_LPC4088.cpp
+void usb_ram_free(void* p);
+
+struct TBUF {
+    uint8_t buf[0];
+    TBUF(const void* data = NULL, int size = 0);
+    void* operator new(size_t size, int buf_size) { return usb_ram_malloc(size+buf_size, 4); }
+    void operator delete(void* p) { usb_ram_free(p); }
+};
+
+class HCED;
+
+struct HCTD {    // HostController Transfer Descriptor
+    __IO uint32_t Control;    // +0 Transfer descriptor control
+    __IO uint8_t* CurrBufPtr; // +4 Physical address of current buffer pointer
+    HCTD* Next;               // +8 Physical pointer to next Transfer Descriptor
+    uint8_t*  BufEnd;         // +12 Physical address of end of buffer
+    uint8_t* buf_top;         // +16 Buffer start address
+    uint16_t buf_size;        // +20 buffer size size
+    uint8_t _dummy[10];       // +22 dummy
+    HCED* parent;             // +32 HCED object
+                              // +36
+    HCTD(HCED* ed);
+    void* operator new(size_t size) { return usb_ram_malloc(size, 16); }
+    void operator delete(void* p) { usb_ram_free(p); }
+
+    void transfer(TBUF* tbuf, int len) {
+        CurrBufPtr = tbuf->buf;
+        buf_top = tbuf->buf;
+        buf_size = len;
+        BufEnd = const_cast<uint8_t*>(tbuf->buf)+len-1;
+    }
+    int getLengthTransferred() {
+        if (CurrBufPtr) {
+            return CurrBufPtr - buf_top;
+        }
+        return buf_size;
+    }
+    int status() {
+        if (CurrBufPtr) {
+            return CurrBufPtr - buf_top;
+        }
+        return buf_size;
+    }
+    
+    uint8_t ConditionCode() {
+        return Control>>28;
+    }    
+}; 
+
+struct HCITD {    // HostController Isochronous Transfer Descriptor
+    __IO uint32_t Control;      // +0 Transfer descriptor control
+    uint8_t*  BufferPage0;      // +4 Buffer Page 0
+    HCITD* Next;                // +8 Physical pointer to next Isochronous Transfer Descriptor
+    uint8_t*  BufferEnd;        // +12 buffer End
+    __IO uint16_t OffsetPSW[8]; // +16 Offset/PSW
+    HCED* parent;               // +32 HCED object
+    __IO uint8_t buf[0];        // +36 buffer
+                                // +36
+    HCITD(HCED* ed, uint16_t FrameNumber, int FrameCount, uint16_t PacketSize);
+    uint8_t* Buffer(int fc);
+    void* operator new(size_t size, int buf_size) { return usb_ram_malloc(size+buf_size, 32); }
+    void operator delete(void* p) { usb_ram_free(p); }
+
+    uint16_t StartingFrame() {
+        return Control & 0xffff;
+    }
+
+    uint8_t FrameCount() {
+        return ((Control>>24)&7)+1;
+    }    
+
+    uint8_t ConditionCode() {
+        return Control>>28;
+    }
+
+    uint8_t ConditionCode(int fc) {
+        uint16_t psw = OffsetPSW[fc];
+        return psw>>12;
+    }
+
+    uint16_t Length(int fc) {
+        uint16_t psw = OffsetPSW[fc];
+        return psw & 0x7ff;
+    }
+};
+
+#define HCTD_QUEUE_SIZE 3
+
+struct HCED {    // HostController EndPoint Descriptor
+    __IO uint32_t Control; // +0 Endpoint descriptor control
+    HCTD* TailTd;          // +4 Physical address of tail in Transfer descriptor list
+    __IO HCTD* HeadTd;     // +8 Physcial address of head in Transfer descriptor list
+    HCED* Next;            // +12 Physical address of next Endpoint descriptor
+                           // +16
+    uint8_t m_ConditionCode;
+    Queue<HCTD, HCTD_QUEUE_SIZE> _done_queue; // TD done queue
+    struct {
+        uint8_t queue_count;
+        uint8_t queue_limit;
+        uint16_t FrameNumber;
+        uint8_t FrameCount; // 1-8
+        HCITD* Current_itd;
+        uint8_t Current_FrameCount;
+    } iso;
+    inline osEvent done_queue_get(uint32_t millisec) { return _done_queue.get(millisec); }
+    inline void irqWdhHandler(HCTD* td) {_done_queue.put(td);} // WDH
+    HCTD* get_queue_HCTD(uint32_t millisec=osWaitForever);
+    HCITD* get_queue_HCITD();
+    HCITD* new_HCITD();
+    HCED(USBEndpoint* ep);
+    void* operator new(size_t size) { return usb_ram_malloc(size, 16); }
+    void operator delete(void* p) { usb_ram_free(p); }
+
+    uint8_t FunctionAddress() {
+        return Control & 0x7f;
+    }
+
+    uint8_t EndpointNumber() {
+        return (Control>>7) & 0x7f;
+    }
+
+    int Speed() {
+        return (Control>>13)&1;
+    }
+
+    void setFunctionAddress(int addr) {
+        Control &= ~0x7f;
+        Control |= addr;
+    }
+
+    void setMaxPacketSize(uint16_t size) {
+        Control &= ~0x07ff0000;
+        Control |= size<<16;
+    }
+
+    uint16_t getMaxPacketSize() {
+        return (Control>>16)&0x7ff;
+    }
+
+    void setToggle(uint8_t toggle);
+    uint8_t getToggle();
+
+    int Skip() {
+        return (Control>>14) & 1;
+    }
+
+    void setSkip() {
+        Control |= (1<<14);
+    }
+
+    void setFormat() {
+        Control |= (1<<15);
+    }
+
+    bool enqueue(HCTD* td);
+    void init_queue(HCTD* td);
+};
+
+struct HCCA {    // Host Controller Communication Area
+    HCED* InterruptTable[32]; // +0 Interrupt Table
+    __IO uint16_t FrameNumber;// +128 Frame Number
+    __IO uint16_t Pad1;       // +130
+    __IO HCTD* DoneHead;      // +132 Done Head
+    uint8_t Reserved[116];    // +136 Reserved for future use
+    uint8_t Unknown[4];       // +252 Unused
+                              // +256
+    void* operator new(size_t size) { return usb_ram_malloc(size, 256); }
+    void operator delete(void* p) { usb_ram_free(p); }
+    void enqueue(HCED* ed);
+};
+
+class USBHALHost {
+protected:
+    USBHALHost();
+    void init();
+    virtual bool addDevice(USBDeviceConnected* parent, int port, bool lowSpeed) = 0;
+    int token_setup(USBEndpoint* ep, SETUP_PACKET* setup, uint16_t wLength = 0);
+    int token_iso_in(USBEndpoint* ep, uint8_t* data, int size);
+    int multi_token_in(USBEndpoint* ep, uint8_t* data = NULL, int size = 0);
+    int multi_token_out(USBEndpoint* ep, const uint8_t* data = NULL, int size = 0);
+    void multi_token_inNB(USBEndpoint* ep, uint8_t* data, int size);
+    USB_TYPE multi_token_inNB_result(USBEndpoint* ep);
+    void setToggle(USBEndpoint* ep, uint8_t toggle);
+
+    // report
+    uint32_t m_report_irq; 
+    uint32_t m_report_RHSC;
+    uint32_t m_report_FNO; 
+    uint32_t m_report_WDH;  
+    uint32_t m_report_sp;
+
+private:
+    void init_hw_ohci(HCCA* pHcca);
+    void ResetRootHub();
+    void token_init(USBEndpoint* ep);
+    static void _usbisr(void);
+    void UsbIrqhandler();
+    HCCA* m_pHcca;
+    bool wait_attach();
+    bool root_lowSpeed;
+    static USBHALHost * instHost;
+};
+
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/USBHost.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHost/USBHost.cpp	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,351 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "USBHost.h"
+
+#define USB_TRACE1(A) while(0)
+#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__);}
+
+USBHost* USBHost::inst = NULL;
+
+USBHost* USBHost::getHostInst() {
+    if (inst == NULL) {
+        inst = new USBHost();
+        inst->init();
+    }
+    return inst;
+}
+
+void USBHost::poll()
+{
+    if (inst) {
+        inst->task();
+    }
+}
+
+USBHost::USBHost() {
+}
+
+/* virtual */ bool USBHost::addDevice(USBDeviceConnected* parent, int port, bool lowSpeed) {
+    USBDeviceConnected* dev = new USBDeviceConnected;
+    USBEndpoint* ep = new USBEndpoint(dev);
+    dev->init(0, port, lowSpeed);
+    dev->setAddress(0);
+    dev->setEpCtl(ep);
+    uint8_t desc[18];
+    wait_ms(100);
+
+    int rc = controlRead(dev, 0x80, GET_DESCRIPTOR, 1<<8, 0, desc, 8);
+    USB_TEST_ASSERT(rc == USB_TYPE_OK);
+    if (rc != USB_TYPE_OK) {
+        USB_ERR("ADD DEVICE FAILD");
+    }
+    USB_DBG_HEX(desc, 8);
+    DeviceDescriptor* dev_desc = reinterpret_cast<DeviceDescriptor*>(desc);
+    ep->setSize(dev_desc->bMaxPacketSize);
+
+    int new_addr = USBDeviceConnected::getNewAddress();
+    rc = controlWrite(dev, 0x00, SET_ADDRESS, new_addr, 0, NULL, 0);
+    USB_TEST_ASSERT(rc == USB_TYPE_OK);
+    dev->setAddress(new_addr);
+    wait_ms(100);
+
+    rc = controlRead(dev, 0x80, GET_DESCRIPTOR, 1<<8, 0, desc, sizeof(desc));
+    USB_TEST_ASSERT(rc == USB_TYPE_OK);
+    USB_DBG_HEX(desc, sizeof(desc));
+
+    dev->setVid(dev_desc->idVendor);
+    dev->setPid(dev_desc->idProduct);
+    dev->setClass(dev_desc->bDeviceClass);
+    USB_INFO("parent:%p port:%d speed:%s VID:%04x PID:%04x class:%02x addr:%d",
+        parent, port, (lowSpeed ? "low " : "full"), dev->getVid(), dev->getPid(), dev->getClass(),
+        dev->getAddress());
+
+    DeviceLists.push_back(dev);
+
+    if (dev->getClass() == HUB_CLASS) {
+        const int config = 1;
+        int rc = controlWrite(dev, 0x00, SET_CONFIGURATION, config, 0, NULL, 0);
+        USB_TEST_ASSERT(rc == USB_TYPE_OK);
+        wait_ms(100);
+        Hub(dev);
+    }
+    return true;
+}
+
+// enumerate a device with the control USBEndpoint
+USB_TYPE USBHost::enumerate(USBDeviceConnected * dev, IUSBEnumerator* pEnumerator)
+{
+    if (dev->getClass() == HUB_CLASS) { // skip hub class
+        return USB_TYPE_OK;
+    }
+    uint8_t desc[18];
+    USB_TYPE rc = controlRead(dev, 0x80, GET_DESCRIPTOR, 1<<8, 0, desc, sizeof(desc));
+    USB_TEST_ASSERT(rc == USB_TYPE_OK);
+    USB_DBG_HEX(desc, sizeof(desc));
+    if (rc != USB_TYPE_OK) {
+        return rc;
+    }
+    DeviceDescriptor* dev_desc = reinterpret_cast<DeviceDescriptor*>(desc);
+    dev->setClass(dev_desc->bDeviceClass);
+    pEnumerator->setVidPid(dev->getVid(), dev->getPid());
+
+    rc = controlRead(dev, 0x80, GET_DESCRIPTOR, 2<<8, 0, desc, 4);
+    USB_TEST_ASSERT(rc == USB_TYPE_OK);
+    USB_DBG_HEX(desc, 4);
+
+    int TotalLength = desc[2]|desc[3]<<8;
+    uint8_t* buf = new uint8_t[TotalLength];
+    rc = controlRead(dev, 0x80, GET_DESCRIPTOR, 2<<8, 0, buf, TotalLength);
+    USB_TEST_ASSERT(rc == USB_TYPE_OK);
+    //USB_DBG_HEX(buf, TotalLength);
+
+    // Parse the configuration descriptor
+    parseConfDescr(dev, buf, TotalLength, pEnumerator);
+    delete[] buf;
+    // only set configuration if not enumerated before
+    if (!dev->isEnumerated()) {
+        USB_DBG("Set configuration 1 on dev: %p", dev);
+        // sixth step: set configuration (only 1 supported)
+        int config = 1;
+        USB_TYPE res = controlWrite(dev, 0x00, SET_CONFIGURATION, config, 0, NULL, 0);
+        if (res != USB_TYPE_OK) {
+            USB_ERR("SET CONF FAILED");
+            return res;
+        }
+        // Some devices may require this delay
+        wait_ms(100);
+        dev->setEnumerated();
+        // Now the device is enumerated!
+        USB_DBG("dev %p is enumerated", dev);
+    }
+    return USB_TYPE_OK;
+}
+
+// this method fills the USBDeviceConnected object: class,.... . It also add endpoints found in the descriptor.
+void USBHost::parseConfDescr(USBDeviceConnected * dev, uint8_t * conf_descr, uint32_t len, IUSBEnumerator* pEnumerator)
+{
+    uint32_t index = 0;
+    uint32_t len_desc = 0;
+    uint8_t id = 0;
+    USBEndpoint * ep = NULL;
+    uint8_t intf_nb = 0;
+    bool parsing_intf = false;
+    uint8_t current_intf = 0;
+    EndpointDescriptor* ep_desc;
+
+    while (index < len) {
+        len_desc = conf_descr[index];
+        id = conf_descr[index+1];
+        USB_DBG_HEX(conf_descr+index, len_desc);
+        switch (id) {
+            case CONFIGURATION_DESCRIPTOR:
+                USB_DBG("dev: %p has %d intf", dev, conf_descr[4]);
+                dev->setNbIntf(conf_descr[4]);
+                break;
+            case INTERFACE_DESCRIPTOR:
+                if(pEnumerator->parseInterface(conf_descr[index + 2], conf_descr[index + 5], conf_descr[index + 6], conf_descr[index + 7])) {
+                    intf_nb++;
+                    current_intf = conf_descr[index + 2];
+                    dev->addInterface(current_intf, conf_descr[index + 5], conf_descr[index + 6], conf_descr[index + 7]);
+                    USB_DBG("ADD INTF %d on device %p: class: %d, subclass: %d, proto: %d", current_intf, dev, conf_descr[index + 5],conf_descr[index + 6],conf_descr[index + 7]);
+                    parsing_intf = true;
+                } else {
+                    parsing_intf = false;
+                }
+                break;
+            case ENDPOINT_DESCRIPTOR:
+                ep_desc = reinterpret_cast<EndpointDescriptor*>(conf_descr+index);
+                if (parsing_intf && (intf_nb <= MAX_INTF) ) {
+                    ENDPOINT_TYPE type = (ENDPOINT_TYPE)(ep_desc->bmAttributes & 0x03);
+                    ENDPOINT_DIRECTION dir = (ep_desc->bEndpointAddress & 0x80) ? IN : OUT;
+                    if(pEnumerator->useEndpoint(current_intf, type, dir)) {
+                        ep = new USBEndpoint(dev);
+                        ep->init(type, dir, ep_desc->wMaxPacketSize, ep_desc->bEndpointAddress);
+                        USB_DBG("ADD USBEndpoint %p, on interf %d on device %p", ep, current_intf, dev);
+                        dev->addEndpoint(current_intf, ep);
+                    }
+                }
+                break;
+            case HID_DESCRIPTOR:
+                //lenReportDescr = conf_descr[index + 7] | (conf_descr[index + 8] << 8);
+                break;
+            default:
+                break;
+        }
+        index += len_desc;
+    }
+}
+
+USB_TYPE USBHost::controlRead(USBDeviceConnected* dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len) {
+    USBEndpoint* ep = dev->getEpCtl();
+    SETUP_PACKET setup(requestType, request, value, index, len);
+
+    int result = token_setup(ep, &setup, len); // setup stage
+    USB_TRACE1(result);
+    if (result < 0) {
+        return USB_TYPE_ERROR;
+    }
+
+    int read_len = multi_token_in(ep, buf, len); // data stage
+    USB_TRACE1(read_len);
+    if (read_len < 0) {
+        return USB_TYPE_ERROR;
+    }
+
+    setToggle(ep, 1); // DATA1
+    result = multi_token_out(ep); // status stage
+    USB_TRACE1(result);
+    if (result < 0) {
+        return USB_TYPE_ERROR;
+    }
+    ep->setLengthTransferred(read_len);
+    return USB_TYPE_OK;
+}
+
+USB_TYPE USBHost::controlWrite(USBDeviceConnected* dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len) {
+    USBEndpoint* ep = dev->getEpCtl();
+    SETUP_PACKET setup(requestType, request, value, index, len);
+
+    int result = token_setup(ep, &setup, len); // setup stage
+    USB_TRACE1(result);
+    if (result < 0) {
+        return USB_TYPE_ERROR;
+    }
+    int write_len = 0;
+    if (buf != NULL) {
+        write_len = multi_token_out(ep, buf, len); // data stage
+        USB_TRACE1(write_len);
+        if (write_len < 0) {
+            return USB_TYPE_ERROR;
+        }
+    }
+
+    setToggle(ep, 1); // DATA1
+    result = multi_token_in(ep); // status stage
+    USB_TRACE1(result);
+    if (result < 0) {
+        return USB_TYPE_ERROR;
+    }
+    ep->setLengthTransferred(write_len);
+    return USB_TYPE_OK;
+}
+
+USB_TYPE USBHost::bulkRead(USBDeviceConnected* dev, USBEndpoint* ep, uint8_t* buf, uint32_t len, bool blocking) {
+    if (blocking == false) {
+        ep->setBuffer(buf, len);
+        ep_queue.push(ep);
+        multi_token_inNB(ep, buf, len);
+        return USB_TYPE_PROCESSING;
+    }
+    int result = multi_token_in(ep, buf, len);
+    USB_TRACE1(result);
+    if (result < 0) {
+        return USB_TYPE_ERROR;
+    }
+    ep->setLengthTransferred(result);
+    return USB_TYPE_OK;
+}
+
+USB_TYPE USBHost::bulkWrite(USBDeviceConnected* dev, USBEndpoint* ep, uint8_t* buf, uint32_t len, bool blocking) {
+    USB_TEST_ASSERT(blocking);
+    int result = multi_token_out(ep, buf, len);
+    USB_TRACE1(result);
+    if (result < 0) {
+        return USB_TYPE_ERROR;
+    }
+    ep->setLengthTransferred(result);
+    return USB_TYPE_OK;
+}
+
+USB_TYPE USBHost::interruptRead(USBDeviceConnected* dev, USBEndpoint* ep, uint8_t* buf, uint32_t len, bool blocking) {
+    if (blocking == false) {
+        ep->setBuffer(buf, len);
+        ep_queue.push(ep);
+        multi_token_inNB(ep, buf, len);
+        return USB_TYPE_PROCESSING;
+    }
+    int result = multi_token_in(ep, buf, len);
+    USB_TRACE1(result);
+    if (result < 0) {
+        return USB_TYPE_ERROR;
+    }
+    ep->setLengthTransferred(result);
+    return USB_TYPE_OK;
+}
+
+USB_TYPE USBHost::interruptWrite(USBDeviceConnected* dev, USBEndpoint* ep, uint8_t* buf, uint32_t len, bool blocking) {
+    USB_TEST_ASSERT(blocking);
+    int result = multi_token_out(ep, buf, len);
+    USB_TRACE1(result);
+    if (result < 0) {
+        return USB_TYPE_ERROR;
+    }
+    ep->setLengthTransferred(result);
+    return USB_TYPE_OK;
+}
+
+USB_TYPE USBHost::isochronousRead(USBDeviceConnected* dev, USBEndpoint* ep, uint8_t* buf, uint32_t len, bool blocking) {
+    USB_TEST_ASSERT(blocking);
+    isochronousReadNB(ep, buf, len);
+    return USB_TYPE_OK;
+}
+
+int USBHost::interruptReadNB(USBEndpoint* ep, uint8_t* data, int size) {
+    USB_TRACE1(size);
+    if (ep->getState() != USB_TYPE_PROCESSING) {
+        ep->setState(USB_TYPE_PROCESSING);
+        ep->setBuffer(data, size);
+        multi_token_inNB(ep, data, size);
+    }
+    if (multi_token_inNB_result(ep) != USB_TYPE_PROCESSING) {
+        return ep->getLengthTransferred();
+    }
+    return -1;
+}
+
+int USBHost::bulkReadNB(USBEndpoint* ep, uint8_t* data, int size) {
+    USB_TRACE1(size);
+    return interruptReadNB(ep, data, size);
+}
+
+int USBHost::isochronousReadNB(USBEndpoint* ep, uint8_t* data, int size) {
+    USB_TRACE1(size);
+    int result = token_iso_in(ep, data, size);
+    if (result >= 0) {
+         ep->setLengthTransferred(result);
+    }
+    return result;
+}
+
+void USBHost::task() {
+    USBEndpoint* ep = ep_queue.pop();
+    if (ep) {
+        USB_TEST_ASSERT(ep->getDir() == IN);
+        if (multi_token_inNB_result(ep) != USB_TYPE_PROCESSING) {
+            ep->call();
+        } else {
+            ep_queue.push(ep);
+        }
+    }
+}
+
+void usb_test_assert_internal(const char *expr, const char *file, int line){
+    error("\n\n%s@%d %s ASSERT!\n\n", file, line, expr);
+}
+
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/USBHost.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHost/USBHost.h	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,194 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+#include "mbed.h"
+#include "USBHALHost.h"
+#include "USBDeviceConnected.h"
+#include "IUSBEnumerator.h"
+#include "USBHostConf.h"
+#include "dbg.h"
+#include "myvector.h"
+
+/**
+* USBHost class
+*   This class is a singleton. All drivers have a reference on the static USBHost instance
+*/
+class USBHost : public USBHALHost {
+public:
+    /**
+    * Static method to create or retrieve the single USBHost instance
+    */
+    static USBHost* getHostInst();
+
+    /**
+    * Control read: setup stage, data stage and status stage
+    *
+    * @param dev the control read will be done for this device
+    * @param requestType request type
+    * @param request request
+    * @param value value
+    * @param index index
+    * @param buf pointer on a buffer where will be store the data received
+    * @param len length of the transfer
+    *
+    * @returns status of the control read
+    */
+    USB_TYPE controlRead(USBDeviceConnected * dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len);
+
+    /**
+    * Control write: setup stage, data stage and status stage
+    *
+    * @param dev the control write will be done for this device
+    * @param requestType request type
+    * @param request request
+    * @param value value
+    * @param index index
+    * @param buf pointer on a buffer which will be written
+    * @param len length of the transfer
+    *
+    * @returns status of the control write
+    */
+    USB_TYPE controlWrite(USBDeviceConnected * dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len);
+
+    /**
+    * Bulk read
+    *
+    * @param dev the bulk transfer will be done for this device
+    * @param ep USBEndpoint which will be used to read a packet
+    * @param buf pointer on a buffer where will be store the data received
+    * @param len length of the transfer
+    * @param blocking if true, the read is blocking (wait for completion)
+    *
+    * @returns status of the bulk read
+    */
+    USB_TYPE bulkRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true);
+
+    /**
+    * Bulk write
+    *
+    * @param dev the bulk transfer will be done for this device
+    * @param ep USBEndpoint which will be used to write a packet
+    * @param buf pointer on a buffer which will be written
+    * @param len length of the transfer
+    * @param blocking if true, the write is blocking (wait for completion)
+    *
+    * @returns status of the bulk write
+    */
+    USB_TYPE bulkWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true);
+
+    /**
+    * Interrupt read
+    *
+    * @param dev the interrupt transfer will be done for this device
+    * @param ep USBEndpoint which will be used to write a packet
+    * @param buf pointer on a buffer which will be written
+    * @param len length of the transfer
+    * @param blocking if true, the read is blocking (wait for completion)
+    *
+    * @returns status of the interrupt read
+    */
+    USB_TYPE interruptRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true);
+
+    /**
+    * Interrupt write
+    *
+    * @param dev the interrupt transfer will be done for this device
+    * @param ep USBEndpoint which will be used to write a packet
+    * @param buf pointer on a buffer which will be written
+    * @param len length of the transfer
+    * @param blocking if true, the write is blocking (wait for completion)
+    *
+    * @returns status of the interrupt write
+    */
+    USB_TYPE interruptWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true);
+
+    /**
+    * Isochronous read
+    *
+    * @param dev the isochronous transfer will be done for this device
+    * @param ep USBEndpoint which will be used to write a packet
+    * @param buf pointer on a buffer which will be written
+    * @param len length of the transfer
+    * @param blocking if true, the read is blocking (wait for completion)
+    *
+    * @returns status of the interrupt read
+    */
+    USB_TYPE isochronousRead(USBDeviceConnected* dev, USBEndpoint* ep, uint8_t* buf, uint32_t len, bool blocking = true);
+
+    /**
+    * Enumerate a device.
+    *
+    * @param dev device which will be enumerated
+    *
+    * @returns status of the enumeration
+    */
+    USB_TYPE enumerate(USBDeviceConnected * dev, IUSBEnumerator* pEnumerator);
+
+    /**
+    * Get a device
+    *
+    * @param index index of the device which will be returned
+    *
+    * @returns pointer on the "index" device
+    */
+    USBDeviceConnected * getDevice(uint8_t index) {
+        return index < DeviceLists.size() ? DeviceLists[index] : NULL;
+    }
+
+    /**
+     *  register a driver into the host associated with a callback function called when the device is disconnected
+     *
+     *  @param dev device
+     *  @param intf interface number
+     *  @param tptr pointer to the object to call the member function on
+     *  @param mptr pointer to the member function to be called
+     */
+    template<typename T>
+    void registerDriver(USBDeviceConnected * dev, uint8_t intf, T* tptr, void (T::*mptr)(void)) {
+    }
+
+    // KL46Z-USBHost extensions
+    int interruptReadNB(USBEndpoint* ep, uint8_t* data, int size);
+    int bulkReadNB(USBEndpoint*ep, uint8_t* data, int size);
+    int isochronousReadNB(USBEndpoint*ep, uint8_t* data, int size);
+
+    /**
+     * non-blocking processing
+     */
+    static void poll();
+
+private:
+    USBHost();
+    static USBHost* inst;
+    virtual bool addDevice(USBDeviceConnected* parent, int port, bool lowSpeed);
+    void root_enumeration(USBDeviceConnected* dev);
+    void parseConfDescr(USBDeviceConnected* dev, uint8_t* conf_descr, uint32_t len, IUSBEnumerator* pEnumerator);
+    myvector<USBDeviceConnected*>DeviceLists;
+    void task();
+    EndpointQueue ep_queue;
+
+    // USB HUB
+    bool Hub(USBDeviceConnected* dev);
+    int SetPortPower(USBDeviceConnected* dev, int port);
+    int ClearPortPower(USBDeviceConnected* dev, int port);
+    int PortReset(USBDeviceConnected* dev, int port);
+    int SetPortFeature(USBDeviceConnected* dev, int feature, int index);
+    int ClearPortFeature(USBDeviceConnected* dev, int feature, int index);
+    int SetPortReset(USBDeviceConnected* dev, int port);
+    int GetPortStatus(USBDeviceConnected* dev, int port, uint32_t* status);
+};
+
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/USBHostConf.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHost/USBHostConf.h	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,71 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef USBHOST_CONF_H
+#define USBHOST_CONF_H
+
+/*
+* Maximum number of devices that can be connected
+* to the usb host
+*/
+#define MAX_DEVICE_CONNECTED        5
+
+/*
+* Maximum of Hub connected to the usb host
+*/
+#define MAX_HUB_NB                  2
+
+/*
+* Maximum number of ports on a USB hub
+*/
+#define MAX_HUB_PORT                4
+
+/*
+* Enable USBHostMSD
+*/
+#define USBHOST_MSD                 1
+
+/*
+* Enable USBHostKeyboard
+*/
+#define USBHOST_KEYBOARD            1
+
+/*
+* Enable USBHostMouse
+*/
+#define USBHOST_MOUSE               1
+
+/*
+* Enable USBHostSerial or USBHostMultiSerial (if set > 1)
+*/
+#define USBHOST_SERIAL              1
+
+/*
+* Enable USB3Gmodule
+*/
+#define USBHOST_3GMODULE            1 
+
+/*
+* Maximum number of interfaces of a usb device
+*/
+#define MAX_INTF                    4
+
+/*
+* usb_thread stack size
+*/
+#define USB_THREAD_STACK            (256*4 + MAX_HUB_NB*256*4)
+
+#endif
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/USBHostHub.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHost/USBHostHub.cpp	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,112 @@
+#include "USBHost.h"
+
+#define PORT_CONNECTION   0
+#define PORT_ENABLE       1
+#define PORT_SUSPEND      2
+#define PORT_OVER_CURRENT 3
+#define PORT_RESET        4
+#define PORT_POWER        8
+#define PORT_LOW_SPEED    9
+
+#define C_PORT_CONNECTION   16
+#define C_PORT_ENABLE       17
+#define C_PORT_SUSPEND      18
+#define C_PORT_OVER_CURRENT 19
+#define C_PORT_RESET        20
+
+bool USBHost::Hub(USBDeviceConnected* dev) {
+    USB_INFO("New HUB: VID:%04x PID:%04x [dev: %p]", dev->getVid(), dev->getPid(), dev);
+    HubDescriptor hubdesc;
+    // get HUB descriptor
+    int rc = controlRead(dev, 
+                        USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS,
+                        GET_DESCRIPTOR,
+                        0x29 << 8, 0, reinterpret_cast<uint8_t*>(&hubdesc), 
+                        sizeof(HubDescriptor));
+    USB_TEST_ASSERT(rc == USB_TYPE_OK);
+    if (rc != USB_TYPE_OK) {
+        return false;
+    }
+    USB_DBG_HEX((uint8_t*)&hubdesc, sizeof(hubdesc));
+
+    uint32_t status;
+    rc = controlRead( dev,
+                      0xa0, 0, 0, 0, reinterpret_cast<uint8_t*>(&status), 4);
+    USB_TEST_ASSERT(rc == USB_TYPE_OK);
+    if (rc != USB_TYPE_OK) {
+        return false;
+    }
+    USB_DBG("HUB STATUS: %08X\n", status);
+
+    for(int i = 1; i <= hubdesc.bNbrPorts; i++) {
+        SetPortPower(dev, i); // power on
+        wait_ms(hubdesc.bPwrOn2PwrGood*2);
+        uint32_t status;
+        GetPortStatus(dev, i, &status);
+        USB_DBG("port: %d status: %08X\n", i, status);
+        if (status & 0x010000) { // Connect Status Change, has changed
+            USB_TEST_ASSERT(status & 0x000001);
+            ClearPortFeature(dev, C_PORT_CONNECTION, i);
+            int lowSpeed = 0;
+            if (status & 0x0200) {
+                lowSpeed = 1;
+            }
+            PortReset(dev, i);
+            if (!addDevice(dev, i, lowSpeed)) {
+                ClearPortPower(dev, i); // power off
+            }
+        } else {
+            ClearPortPower(dev, i); // power off
+        }
+    }
+    return false;
+}
+
+
+int USBHost::SetPortPower(USBDeviceConnected* dev, int port)
+{
+    return SetPortFeature(dev, PORT_POWER, port);
+}
+
+int USBHost::ClearPortPower(USBDeviceConnected* dev, int port)
+{
+    return ClearPortFeature(dev, PORT_POWER, port);
+}
+
+int USBHost::SetPortFeature(USBDeviceConnected* dev, int feature, int index)
+{
+    return controlWrite(dev, 0x23, SET_FEATURE,feature,index,0,0);
+}
+
+int USBHost::ClearPortFeature(USBDeviceConnected* dev, int feature, int index)
+{
+    return controlWrite(dev, 0x23, CLEAR_FEATURE,feature,index,0,0);
+}
+
+int USBHost::SetPortReset(USBDeviceConnected* dev, int port)
+{
+    return SetPortFeature(dev, PORT_RESET, port);
+}
+
+int USBHost::GetPortStatus(USBDeviceConnected* dev, int port, uint32_t* status)
+{
+    return controlRead(dev, 0xa3, GET_STATUS, 0, port, (uint8_t*)status, 4);
+}
+
+int USBHost::PortReset(USBDeviceConnected* dev, int port)
+{
+    USB_DBG("%p port=%d\n", this, port);
+    USB_TEST_ASSERT(port >= 1);
+    SetPortReset(dev, port);
+    // wait reset
+    for(int i = 0; i < 100; i++) {
+        uint32_t status;    
+        GetPortStatus(dev, port, &status);
+        USB_DBG("RESET port: %d status: %08X\n", port, status);
+        if (status & 0x100000) { // Reset change , Reset complete
+            return USB_TYPE_OK;
+        }
+        wait_ms(5);
+     }
+     return USB_TYPE_ERROR;
+}
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/USBHostTypes.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHost/USBHostTypes.h	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,167 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef USB_INC_H
+#define USB_INC_H
+
+#include "mbed.h"
+#include "toolchain.h"
+
+enum USB_TYPE {
+    USB_TYPE_OK = 0,
+
+    // completion code
+    USB_TYPE_CRC_ERROR = 1,
+    USB_TYPE_BIT_STUFFING_ERROR = 2,
+    USB_TYPE_DATA_TOGGLE_MISMATCH_ERROR = 3,
+    USB_TYPE_STALL_ERROR = 4,
+    USB_TYPE_DEVICE_NOT_RESPONDING_ERROR = 5,
+    USB_TYPE_PID_CHECK_FAILURE_ERROR = 6,
+    USB_TYPE_UNEXPECTED_PID_ERROR = 7,
+    USB_TYPE_DATA_OVERRUN_ERROR = 8,
+    USB_TYPE_DATA_UNDERRUN_ERROR = 9,
+    USB_TYPE_RESERVED = 9,
+    USB_TYPE_RESERVED_ = 10,
+    USB_TYPE_BUFFER_OVERRUN_ERROR = 12,
+    USB_TYPE_BUFFER_UNDERRUN_ERROR = 13,
+
+    // general usb state
+    USB_TYPE_DISCONNECTED = 14,
+    USB_TYPE_FREE = 15,
+    USB_TYPE_IDLE = 16,
+    USB_TYPE_PROCESSING = 17,
+
+    USB_TYPE_ERROR = 18,
+};
+
+
+enum ENDPOINT_DIRECTION {
+    OUT = 1,
+    IN
+};
+
+enum ENDPOINT_TYPE {
+    CONTROL_ENDPOINT = 0,
+    ISOCHRONOUS_ENDPOINT,
+    BULK_ENDPOINT,
+    INTERRUPT_ENDPOINT
+};
+
+#define AUDIO_CLASS     0x01
+#define CDC_CLASS       0x02
+#define HID_CLASS       0x03
+#define MSD_CLASS       0x08
+#define HUB_CLASS       0x09
+#define SERIAL_CLASS    0x0A
+
+#define  DEVICE_DESCRIPTOR                     (1)
+#define  CONFIGURATION_DESCRIPTOR              (2)
+#define  INTERFACE_DESCRIPTOR                  (4)
+#define  ENDPOINT_DESCRIPTOR                   (5)
+#define  HID_DESCRIPTOR                        (33)
+
+//  ----------- Control RequestType Fields  ----------- 
+#define  USB_DEVICE_TO_HOST         0x80
+#define  USB_HOST_TO_DEVICE         0x00
+#define  USB_REQUEST_TYPE_CLASS     0x20
+#define  USB_REQUEST_TYPE_STANDARD  0x00
+#define  USB_RECIPIENT_DEVICE       0x00
+#define  USB_RECIPIENT_INTERFACE    0x01
+#define  USB_RECIPIENT_ENDPOINT     0x02
+
+// -------------- USB Standard Requests  -------------- 
+#define  GET_STATUS                 0x00
+#define  SET_FEATURE                0x03
+#define  SET_ADDRESS                0x05
+#define  GET_DESCRIPTOR             0x06
+#define  SET_CONFIGURATION          0x09
+#define  SET_INTERFACE              0x0b
+#define  CLEAR_FEATURE              0x01
+
+// -------------- USB Descriptor Length  -------------- 
+#define DEVICE_DESCRIPTOR_LENGTH            0x12
+#define CONFIGURATION_DESCRIPTOR_LENGTH     0x09
+
+// PID
+#define DATA0 0x03
+#define DATA1 0x0b
+#define ACK   0x02
+#define STALL 0x0e
+#define NAK   0x0a
+
+#pragma pack(push,1)
+typedef struct {
+    uint8_t bLength;            
+    uint8_t bDescriptorType;    
+    uint16_t bcdUSB;            
+    uint8_t bDeviceClass;       
+    uint8_t bDeviceSubClass;    
+    uint8_t bDeviceProtocol;    
+    uint8_t bMaxPacketSize;     
+    uint16_t idVendor;          
+    uint16_t idProduct;         
+    uint16_t bcdDevice;         
+    uint8_t iManufacturer;      
+    uint8_t iProduct;           
+    uint8_t iSerialNumber;      
+    uint8_t bNumConfigurations; 
+} PACKED DeviceDescriptor;
+
+typedef struct {
+    uint8_t bLength;               
+    uint8_t bDescriptorType;       
+    uint16_t wTotalLength;         
+    uint8_t bNumInterfaces;        
+    uint8_t bConfigurationValue;   
+    uint8_t iConfiguration;        
+    uint8_t bmAttributes;          
+    uint8_t bMaxPower;             
+} PACKED ConfigurationDescriptor; 
+
+typedef struct {
+    uint8_t bLength;                 
+    uint8_t bDescriptorType;   
+    uint8_t bInterfaceNumber;  
+    uint8_t bAlternateSetting; 
+    uint8_t bNumEndpoints;     
+    uint8_t bInterfaceClass;   
+    uint8_t bInterfaceSubClass;
+    uint8_t bInterfaceProtocol;
+    uint8_t iInterface;        
+} InterfaceDescriptor; 
+
+typedef struct {
+    uint8_t bLength;          
+    uint8_t bDescriptorType;  
+    uint8_t bEndpointAddress; 
+    uint8_t bmAttributes;     
+    uint16_t wMaxPacketSize;  
+    uint8_t bInterval;        
+} EndpointDescriptor;
+
+typedef struct {
+    uint8_t bDescLength;      
+    uint8_t bDescriptorType;  
+    uint8_t bNbrPorts;        
+    uint16_t wHubCharacteristics;
+    uint8_t bPwrOn2PwrGood;   
+    uint8_t bHubContrCurrent; 
+    uint8_t DeviceRemovable;  
+    uint8_t PortPweCtrlMak;   
+} HubDescriptor;              
+#pragma pack(pop)
+
+#endif
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/dbg.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHost/dbg.h	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,89 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef USB_DEBUG_H
+#define USB_DEBUG_H
+
+//Debug is disabled by default
+#ifndef DEBUG
+#define DEBUG 3 /*INFO,ERR,WARN*/
+#endif
+#ifndef DEBUG2
+#define DEBUG2 0
+#endif
+#define DEBUG_TRANSFER 0
+#define DEBUG_EP_STATE 0
+#define DEBUG_EVENT 0
+
+#if (DEBUG > 3)
+#define USB_DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\r\n");} while(0);
+//#define USB_DBG(x, ...) std::printf("[USB_DBG: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
+#define USB_DBG_HEX(A,B) debug_hex(A,B)
+extern void debug_hex(uint8_t* buf, int size);
+#define USB_DBG_ERRSTAT() report.print_errstat();
+#else
+#define USB_DBG(x, ...)
+#define USB_DBG_HEX(A,B) while(0)
+#define USB_DBG_ERRSTAT() while(0)
+#endif
+
+#if (DEBUG2 > 3)
+#define USB_DBG2(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\r\n");} while(0);
+#else
+#define USB_DBG2(...)  while(0);
+#endif
+
+#if (DEBUG > 2)
+#define USB_INFO(...) do{fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\r\n");}while(0);
+//#define USB_INFO(x, ...) std::printf("[USB_INFO: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
+#else
+#define USB_INFO(x, ...)
+#endif
+
+#if (DEBUG > 1)
+#define USB_WARN(x, ...) std::printf("[USB_WARNING: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
+#else
+#define USB_WARN(x, ...)
+#endif
+
+#if (DEBUG > 0)
+#define USB_ERR(x, ...) std::printf("[USB_ERR: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
+#else
+#define USB_ERR(x, ...)
+#endif
+
+#if (DEBUG_TRANSFER)
+#define USB_DBG_TRANSFER(x, ...) std::printf("[USB_TRANSFER: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
+#else
+#define USB_DBG_TRANSFER(x, ...)
+#endif
+
+#if (DEBUG_EVENT)
+#define USB_DBG_EVENT(x, ...) std::printf("[USB_EVENT: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
+#else
+#define USB_DBG_EVENT(x, ...)
+#endif
+
+#ifdef _USB_TEST
+#define USB_TEST_ASSERT(A) while(!(A)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);};
+#define USB_TEST_ASSERT_FALSE(A) USB_TEST_ASSERT(!(A))
+#else
+#define USB_TEST_ASSERT(A) while(0)
+#define USB_TEST_ASSERT_FALSE(A) while(0)
+#endif
+
+#endif
+
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/mydebug.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHost/mydebug.h	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,13 @@
+#pragma once
+template<class SERIAL_T>
+void debug_hex(SERIAL_T& pc, const uint8_t* buf, int size)
+{
+    for(int i = 0; i < size; i++) {
+        pc.printf("%02x ", buf[i]);
+        if (i%16 == 15) {
+            pc.puts("\n");
+        }
+    }
+    pc.puts("\n");
+}
+
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/mymap.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHost/mymap.h	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,65 @@
+#pragma once
+
+template<class K,class T>
+class mymap {
+    struct mypair {
+        K first;
+        T second;
+    };
+public:
+    mymap() {
+        m_size = 0;
+    }
+    T& operator[](const K& key) {
+        int it;
+        if (count(key) == 0) {
+            it = insert(key, 0);
+        } else {
+            it = find(key);
+        }
+        return m_buf[it].second;
+    }
+    bool empty() { return m_size == 0 ? true : false; }
+    int size() { return m_size; }
+    void clear() { m_size = 0; }
+    int count(K key) {
+        for(int i = 0; i < m_size; i++) {
+            if (m_buf[i].first == key) {
+                return 1;
+            }
+        }
+        return 0;
+    }
+
+private:
+    int find(K key) {
+        for(int i = 0; i < m_size; i++) {
+            if (m_buf[i].first == key) {
+                return i;
+            }
+        }
+        return -1;
+    }
+    int insert(K key, T value) {
+        int it = find(key);
+        if (it != -1) {
+            m_buf[it].second = value;
+            return it;
+        }
+        mypair* new_buf = new mypair[m_size+1];
+        if (m_size > 0) {
+            for(int i = 0; i < m_size; i++) {
+                new_buf[i] = m_buf[i];
+            }
+            delete[] m_buf;
+        }
+        m_buf = new_buf;
+        it = m_size++;
+        m_buf[it].first = key;
+        m_buf[it].second = value;
+        return it;
+    }
+
+    int m_size;
+    mypair *m_buf;
+};
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHost/myvector.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHost/myvector.h	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,34 @@
+#pragma once
+
+template<class T>
+class myvector {
+public:
+    myvector() {
+        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) {
+            for(int i = 0; i < m_size; i++) {
+                new_buf[i] = m_buf[i];
+            }
+            delete[] m_buf;
+        }
+        m_buf = new_buf;
+        m_buf[m_size++] = v;
+    }
+    T& operator[](const int index) {
+        return m_buf[index];
+    }
+    int size() { return m_size; }
+
+private:
+    int m_size;
+    T *m_buf;
+};
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostC270/BaseUvc.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHostC270/BaseUvc.cpp	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,52 @@
+// BaseUvc.cpp
+#include "USBHostConf.h"
+#include "USBHost.h"
+#include "BaseUvc.h"
+
+void BaseUvc::poll() {
+    uint8_t buf[ep_iso_in->getSize()];
+    int result = host->isochronousReadNB(ep_iso_in, buf, sizeof(buf));
+    if (result >= 0) {
+        const uint16_t frame = 0;
+        onResult(frame, buf, ep_iso_in->getLengthTransferred());
+    }
+}
+
+USB_TYPE BaseUvc::Control(int req, int cs, int index, uint8_t* buf, int size) {
+    if (req == SET_CUR) {    
+        return host->controlWrite(dev,
+                    USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_INTERFACE, 
+                    req, cs<<8, index, buf, size);
+    }
+    return host->controlRead(dev,
+                USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_INTERFACE, 
+                req, cs<<8, index, buf, size);
+}
+
+USB_TYPE BaseUvc::setInterfaceAlternate(uint8_t intf, uint8_t alt) {
+    return host->controlWrite(dev, USB_HOST_TO_DEVICE | USB_RECIPIENT_INTERFACE,
+                                   SET_INTERFACE, alt, intf, NULL, 0);
+}
+
+void BaseUvc::onResult(uint16_t frame, uint8_t* buf, int len)
+{
+  if(m_pCbItem && m_pCbMeth)
+    (m_pCbItem->*m_pCbMeth)(frame, buf, len);
+  else if(m_pCb)
+    m_pCb(frame, buf, len);
+}
+
+void BaseUvc::setOnResult( void (*pMethod)(uint16_t, uint8_t*, int) )
+{
+    m_pCb = pMethod;
+    m_pCbItem = NULL;
+    m_pCbMeth = NULL;
+}
+    
+void BaseUvc::clearOnResult()
+{
+    m_pCb = NULL;
+    m_pCbItem = NULL;
+    m_pCbMeth = NULL;
+}
+
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostC270/BaseUvc.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHostC270/BaseUvc.h	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,50 @@
+// BaseUvc.h
+#pragma once
+
+// --- UVC --------------------------------------------------
+#define _30FPS  333333
+#define _25FPS  400000
+#define _20FPS  500000
+#define _15FPS  666666
+#define _10FPS 1000000
+#define _5FPS  2000000
+#define _1FPS 10000000
+
+#define SET_CUR  0x01
+#define GET_CUR  0x81
+#define GET_MIN  0x82
+#define GET_MAX  0x83
+#define GET_RES  0x84
+#define GET_LEN  0x85
+#define GET_INFO 0x86
+#define GET_DEF  0x87
+
+#define VS_PROBE_CONTROL  0x01
+#define VS_COMMIT_CONTROL 0x02
+
+class BaseUvc {
+public:
+    void poll();
+    USB_TYPE Control(int req, int cs, int index, uint8_t* buf, int size);
+    USB_TYPE setInterfaceAlternate(uint8_t intf, uint8_t alt);
+    //IsochronousEp* m_isoEp;
+    // callback
+    void onResult(uint16_t frame, uint8_t* buf, int len);
+    void setOnResult( void (*pMethod)(uint16_t, uint8_t*, int) );
+    class CDummy;
+    template<class T> 
+    void setOnResult( T* pItem, void (T::*pMethod)(uint16_t, uint8_t*, int) )
+    {
+        m_pCb = NULL;
+        m_pCbItem = (CDummy*) pItem;
+        m_pCbMeth = (void (CDummy::*)(uint16_t, uint8_t*, int)) pMethod;
+    }
+    void clearOnResult();
+    CDummy* m_pCbItem;
+    void (CDummy::*m_pCbMeth)(uint16_t, uint8_t*, int);
+    void (*m_pCb)(uint16_t, uint8_t*, int);
+protected:
+    USBHost * host;
+    USBDeviceConnected * dev;
+    USBEndpoint* ep_iso_in;
+};
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostC270/CamInfo.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHostC270/CamInfo.cpp	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,193 @@
+// CamInfo.cpp
+#include "USBHostCam.h"
+
+// Logitech C270
+#define C270_VID 0x046d
+#define C270_PID 0x0825
+#define C270_160x120 2
+#define C270_176x144 3
+#define C270_320x176 4
+#define C270_320x240 5
+#define C270_352x288 6
+#define C270_432x240 7
+#define C270_640x480 1
+#define C270_544x288 8
+#define C270_640x360 9
+#define C270_752x416 10
+#define C270_800x448 11
+#define C270_800x600 12
+
+#define C270_MJPEG 2
+#define C270_YUV2  1
+
+#define C270_EN  0x81
+#define C270_MPS  192
+#define C270_IF_ALT_192 1
+#define C270_IF_ALT(A) C270_IF_ALT_##A
+
+#define C270_INFO(SIZE) {C270_VID, C270_PID, _##SIZE, 0, \
+    "C270", \
+    C270_MJPEG, \
+    C270_##SIZE, \
+    _5FPS, \
+    C270_EN, \
+    192, \
+    C270_IF_ALT(192), \
+    4, \
+    3}
+
+#define C210_PID 0x819
+#define C210_INFO(SIZE) {C270_VID, C210_PID, _##SIZE, 0, \
+    "C210", \
+    C270_MJPEG, \
+    C270_##SIZE, \
+    _5FPS, \
+    C270_EN, \
+    192, \
+    C270_IF_ALT(192), \
+    4, \
+    3}
+
+// Logitech Qcam Orbit AF QCAM-200R
+#define Q200R_VID 0x046d
+#define Q200R_PID 0x0994
+#define Q200R_160x120 1
+#define Q200R_176x144 2
+#define Q200R_320x240 3
+#define Q200R_352x288 4
+#define Q200R_640x480 5
+#define Q200R_800x600 6
+
+#define Q200R_MJPEG 1
+#define Q200R_YUV2  2
+
+#define Q200R_EN  0x81
+#define Q200R_MPS  192
+#define Q200R_IF_ALT_192 1
+#define Q200R_IF_ALT_384 2
+#define Q200R_IF_ALT_512 3
+#define Q200R_IF_ALT_640 4
+#define Q200R_IF_ALT_800 5
+#define Q200R_IF_ALT_944 6
+#define Q200R_IF_ALT(A) Q200R_IF_ALT_##A
+#define Q200R_INFO(SIZE) {Q200R_VID, Q200R_PID, _##SIZE, 0, \
+    "Q200R", \
+    Q200R_MJPEG, \
+    Q200R_##SIZE, \
+    _5FPS, \
+    Q200R_EN, \
+    192, \
+    Q200R_IF_ALT(192), \
+    4, \
+    3}
+
+//LifeCam VX700 / VX500
+#define VX700_VID 0x045e
+#define VX700_PID 0x074a
+
+#define VX700_160x120 5
+#define VX700_176x144 4
+#define VX700_320x240 3
+#define VX700_352x288 2
+#define VX700_640x480 1
+
+#define VX700_MJPEG 1
+
+#define VX700_EN  0x81
+#define VX700_MPS  128
+#define VX700_IF_ALT_128 1 
+#define VX700_IF_ALT(A) VX700_IF_ALT_##A
+#define VX700_INFO(SIZE) {VX700_VID, VX700_PID, _##SIZE, 0, \
+    "VX700", \
+    VX700_MJPEG, \
+    VX700_##SIZE, \
+    _5FPS, \
+    VX700_EN, \
+    128, \
+    VX700_IF_ALT(128), \
+    4, \
+    3}
+
+//Sonix USB 2.0 Camera
+#define SONIX_160x120 5
+#define SONIX_176x144 4
+#define SONIX_320x240 3
+#define SONIX_352x288 2
+#define SONIX_640x480 1
+
+#define SONIX_IF_ALT_128 1
+#define SONIX_IF_ALT_256 2
+#define SONIX_IF_ALT_512 3
+#define SONIX_IF_ALT_600 4
+#define SONIX_IF_ALT_800 5
+#define SONIX_IF_ALT_956 6
+#define SONIX_IF_ALT(A) SONIX_IF_ALT_##A
+#define SONIX_INFO(SIZE) {0x0c45, 0x62c0, _##SIZE, 0, \
+    "SONIX", \
+    1, \
+    SONIX_##SIZE, \
+    _5FPS, \
+    0x81, \
+    128, \
+    SONIX_IF_ALT(128), \
+    4, \
+    3}
+
+static const CamInfo CamInfoList[] = {
+// Logitech C270
+C270_INFO(160x120),
+C270_INFO(176x144),
+C270_INFO(320x176),
+C270_INFO(320x240),
+C270_INFO(352x288),
+C270_INFO(432x240),
+C270_INFO(640x480),
+C270_INFO(544x288),
+C270_INFO(640x360),
+C270_INFO(752x416),
+C270_INFO(800x448),
+C270_INFO(800x600),
+
+// Logitech C210
+C210_INFO(160x120),
+C210_INFO(176x144),
+C210_INFO(320x176),
+C210_INFO(320x240),
+C210_INFO(352x288),
+C210_INFO(432x240),
+C210_INFO(640x480),
+C210_INFO(544x288),
+C210_INFO(640x360),
+C210_INFO(752x416),
+C210_INFO(800x448),
+C210_INFO(800x600),
+
+// Logitech Qcam Orbit AF QCAM-200R
+Q200R_INFO(160x120),
+Q200R_INFO(176x144),
+Q200R_INFO(320x240),
+Q200R_INFO(352x288),
+Q200R_INFO(640x480),
+Q200R_INFO(800x600),
+
+// LifeCam VX700
+VX700_INFO(160x120),
+VX700_INFO(176x144),
+VX700_INFO(320x240),
+VX700_INFO(352x288),
+VX700_INFO(640x480),
+
+// Sonix USB 2.0 Camera
+SONIX_INFO(160x120),
+SONIX_INFO(176x144),
+SONIX_INFO(320x240),
+SONIX_INFO(352x288),
+SONIX_INFO(640x480),
+
+// Not found
+{0,0,0,0},
+};
+
+CamInfo* getCamInfoList() {
+    return const_cast<CamInfo*>(CamInfoList);
+}
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostC270/USBHostCam.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHostC270/USBHostCam.cpp	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,154 @@
+// USBHostCam.cpp
+#include "USBHostCam.h"
+
+#if 0
+#define CAM_DBG(x, ...) std::printf("[%s:%d]"x"\n", __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
+#else
+#define CAM_DBG(...)  while(0);
+#endif
+#define CAM_INFO(...) do{fprintf(stderr,__VA_ARGS__);}while(0);
+
+CamInfo* getCamInfoList(); // CamInfo.cpp
+
+USBHostCam::USBHostCam(uint8_t size, uint8_t option, CamInfo* user_caminfo)
+{
+    CAM_DBG("size: %d, option: %d", size, option);
+    _caminfo_size = size;
+    _caminfo_option = option;
+    if (user_caminfo) {
+        CamInfoList = user_caminfo;
+    } else {
+        CamInfoList = getCamInfoList();
+    }
+    clearOnResult();
+    host = USBHost::getHostInst();
+    init();
+}
+
+void USBHostCam::init()
+{
+    CAM_DBG("");
+    dev_connected = false;
+    dev = NULL;
+    ep_iso_in = NULL;
+    cam_intf = -1;
+    device_found = false;
+    caminfo_found = false;
+}
+ 
+bool USBHostCam::connected()
+{
+    return dev_connected;
+}
+ 
+bool USBHostCam::connect()
+{
+    if (dev_connected) {
+        return true;
+    }
+ 
+    for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
+        if ((dev = host->getDevice(i)) != NULL) {
+            
+            CAM_DBG("Trying to connect Cam device\r\n");
+            
+            if(host->enumerate(dev, this)) {
+                break;
+            }
+            if (device_found) {
+                USB_INFO("New Cam: %s device: VID:%04x PID:%04x [dev: %p - intf: %d]", caminfo->name, dev->getVid(), dev->getPid(), dev, cam_intf);
+                ep_iso_in = new USBEndpoint(dev); 
+                ep_iso_in->init(ISOCHRONOUS_ENDPOINT, IN, caminfo->mps, caminfo->en);
+                ep_iso_in->ohci_init(caminfo->frameCount, caminfo->queueLimit);
+                uint8_t buf[26];
+                memset(buf, 0, sizeof(buf));
+                buf[2] = caminfo->formatIndex;
+                buf[3] = caminfo->frameIndex;
+                *reinterpret_cast<uint32_t*>(buf+4) = caminfo->interval;
+                USB_TYPE res = Control(SET_CUR, VS_COMMIT_CONTROL, 1, buf, sizeof(buf));
+                if (res != USB_TYPE_OK) {
+                    USB_ERR("SET_CUR VS_COMMIT_CONTROL FAILED");
+                }
+                res = setInterfaceAlternate(1, caminfo->if_alt);
+                if (res != USB_TYPE_OK) {
+                    USB_ERR("SET_INTERFACE FAILED");
+                }
+                dev_connected = true;
+                return true;
+            }
+        }
+    }
+    init();
+    return false;
+}
+
+/*virtual*/ void USBHostCam::setVidPid(uint16_t vid, uint16_t pid)
+{
+    CAM_DBG("vid:%04x,pid:%04x", vid, pid);
+    caminfo = CamInfoList;
+    while(caminfo->vid != 0) {
+        if (caminfo->vid == vid && caminfo->pid == pid && 
+            caminfo->size == _caminfo_size && caminfo->option == _caminfo_option) {
+            caminfo_found = true;
+            break;
+        }
+        caminfo++;
+    }
+}
+ 
+/*virtual*/ bool USBHostCam::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
+{
+    CAM_DBG("intf_nb=%d,intf_class=%02X,intf_subclass=%d,intf_protocol=%d", intf_nb, intf_class, intf_subclass, intf_protocol);
+    if ((cam_intf == -1) && caminfo_found) {
+        cam_intf = intf_nb;
+        device_found = true;
+        return true;
+    }
+    return false;
+}
+ 
+/*virtual*/ bool USBHostCam::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
+{
+    CAM_DBG("intf_nb:%d,type:%d,dir:%d",intf_nb, type, dir);
+    return false;
+}
+
+#define SEQ_READ_IDLE 0
+#define SEQ_READ_EXEC 1
+#define SEQ_READ_DONE 2
+
+int USBHostCam::readJPEG(uint8_t* buf, int size, int timeout_ms) {
+    _buf = buf;
+    _pos = 0;
+    _size = size;
+    _seq = SEQ_READ_IDLE;
+    setOnResult(this, &USBHostCam::callback_motion_jpeg);
+    Timer timeout_t;
+    timeout_t.reset();
+    timeout_t.start();
+    while(timeout_t.read_ms() < timeout_ms && _seq != SEQ_READ_DONE) {
+        poll();
+    } 
+    return _pos;
+}
+
+/* virtual */ void USBHostCam::outputJPEG(uint8_t c, int status) { // from decodeMJPEG
+    if (_seq == SEQ_READ_IDLE) {
+        if (status == JPEG_START) {
+            _pos = 0;
+            _seq = SEQ_READ_EXEC;
+        }
+    }
+    if (_seq == SEQ_READ_EXEC) {
+        if (_pos < _size) {
+            _buf[_pos++] = c;  
+        }  
+        if (status == JPEG_END) {
+            _seq = SEQ_READ_DONE;
+        }
+    }
+}
+
+void USBHostCam::callback_motion_jpeg(uint16_t frame, uint8_t* buf, int len) {
+        inputPacket(buf, len);
+}
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostC270/USBHostCam.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHostC270/USBHostCam.h	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,100 @@
+// USBHostCam.h
+#include "USBHostConf.h"
+#include "USBHost.h"
+#include "BaseUvc.h"
+#include "decodeMJPEG.h"
+#pragma once
+
+#define _160x120 2
+#define _176x144 3
+#define _320x176 4
+#define _320x240 5
+#define _352x288 6
+#define _432x240 7
+#define _640x480 1
+#define _544x288 8
+#define _640x360 9
+#define _752x416 10
+#define _800x448 11
+#define _800x600 12
+
+#define TEST_ASSERT(A) while(!(A)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);};
+
+struct CamInfo {
+    uint16_t vid;
+    uint16_t pid;
+    uint8_t size;
+    uint8_t option;
+//
+    const char* name;
+    uint8_t formatIndex;
+    uint8_t frameIndex;
+    uint32_t interval;
+    uint8_t en;
+    uint8_t mps;
+    uint8_t if_alt;
+    uint8_t frameCount; // ITD frame count 1-8
+    uint8_t queueLimit; // ITD queue limit 1-3
+};
+
+/** 
+ * A class to communicate a Cam
+ */
+class USBHostCam : public IUSBEnumerator, public BaseUvc, public decodeMJPEG {
+public:
+    /**
+    * Constructor
+    *
+    */
+    USBHostCam(uint8_t size = _160x120, uint8_t option = 0, CamInfo* user_caminfo = NULL);
+
+    /**
+    * Check if a Cam device is connected
+    *
+    * @return true if a Cam device is connected
+    */
+    bool connected();
+ 
+    /**
+     * Try to connect to a Cam device
+     *
+     * @return true if connection was successful
+     */
+    bool connect();
+
+    /**
+     * read jpeg image
+     *
+     * @param buf read buffer 
+     * @param size buffer size 
+     * @param timeout_ms timeout default 15sec
+     * @return jpeg size if read success else -1
+     */
+    int readJPEG(uint8_t* buf, int size, int timeout_ms = 15*1000);
+
+protected:
+    //From IUSBEnumerator
+    virtual void setVidPid(uint16_t vid, uint16_t pid);
+    virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
+    virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
+
+private:
+    bool dev_connected;
+ 
+    int cam_intf;
+    bool device_found;
+    bool caminfo_found;
+
+    uint8_t _seq;
+    uint8_t* _buf;
+    int _pos;
+    int _size;
+    CamInfo* CamInfoList;
+    CamInfo* caminfo;
+    uint8_t _caminfo_size;
+    uint8_t _caminfo_option;
+
+    virtual void outputJPEG(uint8_t c, int status); // from decodeMJPEG
+    void callback_motion_jpeg(uint16_t frame, uint8_t* buf, int len);
+    void init();
+};
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostC270/decodeMJPEG.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHostC270/decodeMJPEG.cpp	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,180 @@
+// decodeMJPEG.cpp 2012/12/8
+// decode motion-jpeg to jpeg
+#include "mbed.h"
+#include "decodeMJPEG.h"
+
+#define MARK_SOF0 0xc0
+#define MARK_DHT  0xc4
+#define MARK_RST0 0xd0
+#define MARK_RST7 0xd7
+#define MARK_SOI  0xd8
+#define MARK_EOI  0xd9
+#define MARK_SOS  0xda
+#define MARK_DQT  0xdb
+#define MARK_DRI  0xdd
+#define MARK_APP  0xe0
+ 
+#define SEQ_INIT      0
+#define SEQ_SOI       1
+#define SEQ_FRAME     2
+#define SEQ_MARK      3
+#define SEQ_SEG_LEN   4
+#define SEQ_SEG_LEN2  5
+#define SEQ_SEG_BODY  6
+#define SEQ_SOS       7
+#define SEQ_SOS2      8
+
+static const uint8_t dht[] = {
+0xFF,0xC4,0x01,0xA2,0x00,0x00,0x01,0x05,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,
+0x0B,0x01,0x00,0x03,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,
+0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x10,0x00,
+0x02,0x01,0x03,0x03,0x02,0x04,0x03,0x05,0x05,0x04,0x04,0x00,0x00,0x01,0x7D,0x01,
+0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,
+0x71,0x14,0x32,0x81,0x91,0xA1,0x08,0x23,0x42,0xB1,0xC1,0x15,0x52,0xD1,0xF0,0x24,
+0x33,0x62,0x72,0x82,0x09,0x0A,0x16,0x17,0x18,0x19,0x1A,0x25,0x26,0x27,0x28,0x29,
+0x2A,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,
+0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,
+0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,
+0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,
+0xA9,0xAA,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xC2,0xC3,0xC4,0xC5,0xC6,
+0xC7,0xC8,0xC9,0xCA,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xE1,0xE2,0xE3,
+0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,
+0xFA,0x11,0x00,0x02,0x01,0x02,0x04,0x04,0x03,0x04,0x07,0x05,0x04,0x04,0x00,0x01,
+0x02,0x77,0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,
+0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,0xA1,0xB1,0xC1,0x09,0x23,0x33,
+0x52,0xF0,0x15,0x62,0x72,0xD1,0x0A,0x16,0x24,0x34,0xE1,0x25,0xF1,0x17,0x18,0x19,
+0x1A,0x26,0x27,0x28,0x29,0x2A,0x35,0x36,0x37,0x38,0x39,0x3A,0x43,0x44,0x45,0x46,
+0x47,0x48,0x49,0x4A,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x63,0x64,0x65,0x66,
+0x67,0x68,0x69,0x6A,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x82,0x83,0x84,0x85,
+0x86,0x87,0x88,0x89,0x8A,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0xA2,0xA3,
+0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,
+0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,
+0xD9,0xDA,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xF2,0xF3,0xF4,0xF5,0xF6,
+0xF7,0xF8,0xF9,0xFA,
+};
+
+decodeMJPEG::decodeMJPEG()
+{
+    m_seq = SEQ_INIT;
+}
+
+void decodeMJPEG::inputPacket(const uint8_t* buf, int len)
+{
+    for(int i = 12; i < len; i++) {
+        input(buf[i]);
+    }    
+}
+
+void decodeMJPEG::input(uint8_t c)
+{
+    switch(m_seq) {
+        case SEQ_INIT:
+            if (c == 0xff) {
+                m_seq = SEQ_SOI;
+            }
+            break;
+        case SEQ_SOI:
+            if (c == MARK_SOI) {
+                outputJPEG(0xff, JPEG_START); // start
+                outputJPEG(c);
+                m_bDHT = false;
+                m_seq = SEQ_FRAME;
+            } else {
+                m_seq = SEQ_INIT;
+            }
+            break;
+        case SEQ_FRAME:
+            if (c == 0xff) {
+                m_seq = SEQ_MARK;
+            } else {
+                m_seq = SEQ_INIT;
+            }
+            break;
+        case SEQ_MARK:
+            if (c == MARK_SOI || c == MARK_EOI || c == 0x00) {
+                m_seq = SEQ_INIT;
+                break;
+            }
+            m_mark = c;
+            m_seq = SEQ_SEG_LEN;
+            break;
+        case SEQ_SEG_LEN:
+            m_seg_len = c;
+            m_seq = SEQ_SEG_LEN2;
+            break;
+        case SEQ_SEG_LEN2:
+            m_seg_len <<= 8;
+            m_seg_len |= c;
+            m_seg_len -= 2;
+            m_seg_pos = 0;
+            m_seq = SEQ_SEG_BODY;
+            if (m_mark == MARK_SOS) {
+                if (m_bDHT == false) {
+                    for(int i = 0; i < sizeof(dht); i++) {
+                        outputJPEG(dht[i]);
+                    }    
+                }
+                m_output_desable = false;
+            } else if (m_mark == MARK_DHT) {
+                m_bDHT = true;
+                m_output_desable = false;
+            } else {
+                m_output_desable = false;
+            }
+            if (!m_output_desable) {
+                outputJPEG(0xff);
+                outputJPEG(m_mark);
+                outputJPEG((m_seg_len+2) >> 8);
+                outputJPEG((m_seg_len+2) & 0xff);
+            } 
+            break;
+        case SEQ_SEG_BODY:
+            if (!m_output_desable) {
+                outputJPEG(c);
+            }
+            if (++m_seg_pos < m_seg_len) {
+                break;
+            }
+            if (m_mark == MARK_SOS) {
+                m_seq = SEQ_SOS;
+                break;
+            }
+            m_seq = SEQ_FRAME;
+            break;
+        case SEQ_SOS:
+            if (c == 0xff) {
+                m_seq = SEQ_SOS2;
+                break;
+            }
+            outputJPEG(c);
+            break;
+        case SEQ_SOS2:
+            if (c == 0x00) {
+                outputJPEG(0xff);
+                outputJPEG(0x00);
+                m_seq = SEQ_SOS;
+                break;
+            } else if (c >= MARK_RST0 && c <= MARK_RST7) {
+                outputJPEG(0xff);
+                outputJPEG(c);
+                m_seq = SEQ_SOS;
+                break;
+            } else if (c == MARK_EOI) {
+                outputJPEG(0xff);
+                outputJPEG(c, JPEG_END);
+                m_seq = SEQ_INIT;
+                break;
+            } else if (c == MARK_SOI) {
+                outputJPEG(0xff);
+                outputJPEG(c);
+                m_seq = SEQ_INIT;
+                break;
+            }
+            m_seq = SEQ_INIT;
+            break;
+        default:
+            m_seq = SEQ_INIT;
+            break;
+    }
+}
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostC270/decodeMJPEG.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHostC270/decodeMJPEG.h	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,25 @@
+// decodeMJPEG.h 2012/12/9
+#ifndef DECODE_MJPEG_H
+#define DECODE_MJPEG_H
+
+#define JPEG_NONE  0
+#define JPEG_START 1
+#define JPEG_END   2
+#define JPEG_ERROR 3
+
+class decodeMJPEG {
+public:
+    decodeMJPEG();
+    void inputPacket(const uint8_t* buf, int len);
+    virtual void outputJPEG(uint8_t c, int status = JPEG_NONE) = 0;
+protected:
+    void input(uint8_t c);
+    int m_seq;
+    uint8_t m_mark;
+    uint16_t m_seg_pos; 
+    uint16_t m_seg_len;
+    bool m_bDHT;
+    bool m_output_desable;
+};
+
+#endif // DECODE_MJPEG_H
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostGPS/USBHostGPS.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHostGPS/USBHostGPS.cpp	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,98 @@
+#include "USBHostGPS.h"
+
+USBHostGPS::USBHostGPS(int baud_)
+{
+    host = USBHost::getHostInst();
+    init();
+    baud = baud_;
+}
+
+void USBHostGPS::init() {
+    dev = NULL;
+    bulk_in = NULL;
+    onUpdateRaw = NULL;
+    dev_connected = false;
+    gps_device_found = false;
+    gps_intf = -1;
+}
+
+bool USBHostGPS::connected() {
+    return dev_connected;
+}
+
+bool USBHostGPS::connect() {
+
+    if (dev_connected) {
+        return true;
+    }
+    
+    for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
+        if ((dev = host->getDevice(i)) != NULL) {
+            if(host->enumerate(dev, this)) {
+                break;
+            }
+            if (gps_device_found) {
+                bulk_in = dev->getEndpoint(gps_intf, BULK_ENDPOINT, IN);
+                USB_TEST_ASSERT(bulk_in);
+                // stop bit = 1, parity = none, 8bit
+                uint8_t data[] = {baud&0xff, baud>>8, baud>>16, baud>>24, 0x00, 0x00, 0x08};
+                USB_TYPE rc = host->controlWrite(dev, 0x21, PL2303_SET_LINE_CODING, 0, 0, data, sizeof(data));
+                USB_TEST_ASSERT(rc == USB_TYPE_OK);
+                USB_INFO("New GPS device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, gps_intf);
+                bulk_in->attach(this, &USBHostGPS::rxHandler);
+                host->bulkRead(dev, bulk_in, bulk_buf, bulk_in->getSize(), false);
+                
+                dev_connected = true;
+                return true;
+            }
+        }
+    }
+    init();
+    return false;
+}
+
+void USBHostGPS::rxHandler() {
+    int len = bulk_in->getLengthTransferred();
+    if (onUpdateRaw) {
+        (*onUpdateRaw)((char*)bulk_buf, len);
+    }
+    nmea.inputNMEA((char*)bulk_buf, len);
+
+    if (dev) {
+        host->bulkRead(dev, bulk_in, bulk_buf, bulk_in->getSize(), false);
+    }
+}
+
+/*virtual*/ void USBHostGPS::setVidPid(uint16_t vid, uint16_t pid)
+{
+    USB_DBG("vid:%04x pid:%04x", vid, pid);
+    if (pid == 0x2303) {
+        gps_device_found = true;
+    }
+}
+
+/*virtual*/ bool USBHostGPS::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
+{
+    USB_DBG("intf: %d class: %02x %02x %02x", intf_nb, intf_class, intf_subclass, intf_protocol);
+    if (gps_device_found) {
+        if (gps_intf == -1) {
+            gps_intf = intf_nb;
+            return true;
+        }
+    }    
+    return false;
+}
+
+/*virtual*/ bool USBHostGPS::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
+{
+    USB_DBG("intf_nb=%d type=%d dir=%d", intf_nb, type, dir);
+    if (gps_device_found) {
+        if (intf_nb == gps_intf) {
+            if (type == BULK_ENDPOINT && dir == IN) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostGPS/USBHostGPS.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHostGPS/USBHostGPS.h	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,60 @@
+// Simple USBHost GPS Dongle for FRDM-KL46Z
+#include "USBHost.h"
+#include "decodeNMEA.h"
+
+#define PL2303_SET_LINE_CODING 0x20
+
+class USBHostGPS : public IUSBEnumerator {
+public:
+
+    /**
+    * Constructor
+    */
+    USBHostGPS(int baud = 38400);
+
+    /**
+     * Try to connect a USB GPS device
+     *
+     * @return true if connection was successful
+     */
+    bool connect();
+
+    /**
+    * Check if a USB GPS is connected
+    *
+    * @returns true if a mouse is connected
+    */
+    bool connected();
+
+    int readNMEA(char* data, int size, int timeout_ms) {
+        host->bulkRead(dev, bulk_in, (uint8_t*)data, size);
+        return bulk_in->getLengthTransferred();
+    }
+    void attachEventRaw(void (*ptr)(char* data, int size)) {
+        if (ptr != NULL) {
+            onUpdateRaw = ptr;
+        }
+    }
+
+    decodeNMEA nmea;
+
+protected:
+    //From IUSBEnumerator
+    virtual void setVidPid(uint16_t vid, uint16_t pid);
+    virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
+    virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
+
+private:
+    USBHost * host;
+    USBDeviceConnected* dev;
+    USBEndpoint* bulk_in;
+    bool dev_connected;
+    bool gps_device_found;
+    int gps_intf;
+
+    void rxHandler();
+    void (*onUpdateRaw)(char* data, int size);
+    uint8_t bulk_buf[64];
+    int baud;
+    void init();
+};
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostGPS/decodeNMEA.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHostGPS/decodeNMEA.cpp	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,159 @@
+// decodeNMEA.cpp 2012/12/13
+#include "mbed.h"
+#include "decodeNMEA.h"
+
+#define SEQ_INIT 0
+#define SEQ_DATA 1
+#define SEQ_SUM0 2
+#define SEQ_SUM1 3
+
+#define GPGGA 1
+#define GPGLL 2
+#define GPGSV 3
+#define GPRMC 4
+#define GPVTG 5
+#define GPZDA 6
+
+decodeNMEA::decodeNMEA():m_seq(0) {
+    gprmc_t = 0;
+    update_t = 0;
+    m_status = false;
+}
+
+void decodeNMEA::inputNMEA(char* buf, int len) {
+    for(int i = 0; i < len; i++) {
+        inputNMEA(buf[i]);
+    }
+}
+
+static int ctoh(char c) {
+    if (c >= '0' && c <= '9') {
+        return c-'0';
+    }
+    return c-'A'+10;
+}
+     
+void decodeNMEA::inputNMEA(char c) {
+    switch(m_seq) {
+        case SEQ_INIT:
+            if (c == '$') {
+                m_type = 0;
+                m_row = 0;
+                m_buf_pos = 0;
+                m_sum = 0x00;
+                m_seq = SEQ_DATA;
+            }
+            break;
+        case SEQ_DATA:
+            m_sum ^= c;
+            if (c == ',' || c == '*') {
+                m_buf[m_buf_pos] = '\0';
+                parse(m_type, m_row, m_buf);
+                m_row++;
+                m_buf_pos =0;
+                if (c == '*') { // check sum ?
+                    m_sum ^= c;
+                    m_seq = SEQ_SUM0;
+                }
+            } else {
+                if (m_buf_pos < sizeof(m_buf)-1) {
+                    m_buf[m_buf_pos++] = c;
+                }
+            }
+            break;
+        case SEQ_SUM0:
+            if (ctoh(c) == (m_sum>>4)) {
+                m_seq = SEQ_SUM1;
+            } else {
+                m_seq = SEQ_INIT;
+            }
+            break;
+        case SEQ_SUM1:
+            if (ctoh(c) == (m_sum&0x0f)) {
+                update(m_type, m_row);
+            } else {
+                
+                m_seq = SEQ_INIT;
+            }
+            break;
+        default:
+            m_seq = SEQ_INIT;
+            break;
+    }
+}
+
+float DMMtoDegree(const char *s)
+{
+    char *p = strchr(const_cast<char*>(s), '.');
+    if (p == NULL) {
+        return 0.0;
+    }
+    const uint32_t k[] = {10000,1000,100,10,1};
+    uint32_t i3 = atoi(p+1) * k[strlen(p+1)];
+    uint32_t i2 = atoi(p-2);
+    uint32_t i1 = atoi(s) / 100;
+
+    uint32_t i = i1*10000*60 + (i2*10000 + i3);
+    return i / 10000.0 / 60.0;
+}
+
+void decodeNMEA::parse(int type, int row, char* buf) {
+    if (row == 0) {
+        if (strcmp(buf, "GPRMC") == 0) {
+            m_type = GPRMC;
+            m_status = false;
+        } else {
+            m_type = 0;
+        }
+        return;
+    }
+    if (type == GPRMC) {
+        switch(row) {
+            case 1:
+                tmp_timeinfo.tm_sec = atoi(buf+4);
+                buf[4] = '\0';
+                tmp_timeinfo.tm_min = atoi(buf+2);
+                buf[2] = '\0';
+                tmp_timeinfo.tm_hour = atoi(buf);
+                break;
+            case 2:
+                if (buf[0] == 'A') {
+                    m_status = true;
+                }
+                break;
+            case 3:
+                tmp_lat = DMMtoDegree(buf);
+                break;
+            case 4:
+                if (buf[0] == 'S') {
+                    tmp_lat *= -1;
+                }
+                break;
+            case 5:
+                tmp_lon = DMMtoDegree(buf);
+                break;
+            case 6:
+                if (buf[0] == 'W') {
+                    tmp_lon *= -1;
+                }
+                break;
+            case 9:
+                tmp_timeinfo.tm_year = 2000 - 1900 + atoi(buf+4);
+                buf[4] = '\0';
+                tmp_timeinfo.tm_mon = atoi(buf+2) - 1;
+                buf[2] = '\0';
+                tmp_timeinfo.tm_mday = atoi(buf);
+                break;
+        }
+    }
+}
+
+void decodeNMEA::update(int type, int row) {
+    if (type == GPRMC && m_status) {
+        lat = tmp_lat;
+        lon = tmp_lon;
+        gprmc_t = mktime(&tmp_timeinfo);
+        update_t = gprmc_t;
+    }
+}
+
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostGPS/decodeNMEA.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHostGPS/decodeNMEA.h	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,28 @@
+// decodeNMEA.h 2012/12/15
+#ifndef DECODE_NMEA_H
+#define DECODE_NMEA_H
+
+class decodeNMEA {
+public:
+    decodeNMEA();
+    void inputNMEA(char* buf, int len);
+    void inputNMEA(char c);
+    float lat,lon;
+    time_t gprmc_t;
+    time_t update_t;
+
+private:
+    void parse(int type, int row, char* buf);
+    void update(int type, int row);
+    int m_seq;
+    int m_type;
+    int m_row;
+    uint8_t m_sum;
+    char m_buf[12];
+    int m_buf_pos;
+    bool m_status;
+    float tmp_lat,tmp_lon;
+    struct tm tmp_timeinfo;
+};
+
+#endif // DECODE_NMEA_H
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostHID/USBHostGamepad.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHostHID/USBHostGamepad.cpp	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,254 @@
+/* mbed USBHost Gamepad driver sample
+ * Copyright (c) 2014 Yuuichi Akagawa
+ *
+ * modified from mbed USBHostMouse
+ *
+ * mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "USBHostGamepad.h"
+
+//#if USBHOST_GAMEPAD
+USBHostGamepad::USBHostGamepad()
+{
+    host = USBHost::getHostInst();
+    init();
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void USBHostGamepad::init()
+{
+    dev = NULL;
+    int_in = NULL;
+    onUpdate = NULL;
+    report_id = 0;
+    dev_connected = false;
+    gamepad_device_found = false;
+    gamepad_intf = -1;
+
+    btnX = 0;
+    btnY = 0;
+    btnABCD = 0;
+    btnSpecial = 0;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+bool USBHostGamepad::connected()
+{
+    return dev_connected;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+bool USBHostGamepad::connect()
+{
+    int len_listen;
+
+    if (dev_connected) {
+        return true;
+    }
+
+    for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
+        if ((dev = host->getDevice(i)) != NULL) {
+            if (host->enumerate(dev, this))
+                break;
+
+            if (gamepad_device_found) {
+                int_in = dev->getEndpoint(gamepad_intf, INTERRUPT_ENDPOINT, IN);
+                if (!int_in)
+                    break;
+
+                USB_INFO
+                (
+                    "New Gamepad/Joystick device: VID:%04x PID:%04x [dev: %p - intf: %d]",
+                    dev->getVid(),
+                    dev->getPid(),
+                    dev,
+                    gamepad_intf
+                );
+#if DEBUG > 3
+                //Parse HID Report Descriptor
+
+                parseHidDescr();
+#endif
+                dev->setName("Gamepad", gamepad_intf);
+                host->registerDriver(dev, gamepad_intf, this, &USBHostGamepad::init);
+
+                int_in->attach(this, &USBHostGamepad::rxHandler);
+                len_listen = int_in->getSize();
+                if (len_listen > sizeof(report)) {
+                    len_listen = sizeof(report);
+                }
+
+                host->interruptRead(dev, int_in, report, len_listen, false);
+
+                dev_connected = true;
+                return true;
+            }
+        }
+    }
+
+    init();
+    return false;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void USBHostGamepad::rxHandler()
+{
+    int len_listen = int_in->getSize();
+#if DEBUG > 3
+    USB_DBG("USBHostGamepad::rxHandler() len_listen=%d\r\n", len_listen);
+    for (int i = 0; i < len_listen; i++)
+        printf("%02X ", report[i]);
+    printf("\r\n\r\n");
+#endif
+    if (onUpdate) {
+        (*onUpdate) (report[0], report[1], report[5], report[6]);
+    }
+
+    // update gamepad state
+    btnX = report[0];
+    btnY = report[1];
+    btnABCD = report[5];
+    btnSpecial = report[6];
+
+    if (len_listen > sizeof(report)) {
+        len_listen = sizeof(report);
+    }
+
+    if (dev)
+        host->interruptRead(dev, int_in, report, len_listen, false);
+}
+
+/*virtual*/
+void USBHostGamepad::setVidPid(uint16_t vid, uint16_t pid)
+{
+    // we don't check VID/PID for gamepad driver
+}
+
+/*virtual*/
+bool USBHostGamepad::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol)  //Must return true if the interface should be parsed
+{
+    if ((gamepad_intf == -1) && (intf_class == HID_CLASS) && (intf_subclass == 0x00) && (intf_protocol == 0x00)) {
+        gamepad_intf = intf_nb;
+        return true;
+    }
+
+    return false;
+}
+
+//Must return true if the endpoint will be used
+
+/*virtual*/
+bool USBHostGamepad::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir)
+{
+    if (intf_nb == gamepad_intf) {
+        if (type == INTERRUPT_ENDPOINT && dir == IN) {
+            gamepad_device_found = true;
+            return true;
+        }
+    }
+
+    return false;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+USB_TYPE USBHostGamepad::getReportDescriptor
+(
+    USBDeviceConnected*     dev,
+    uint8_t*                buf,
+    uint16_t                max_len_buf,
+    uint16_t*               len_rep_descr
+)
+{
+    USB_TYPE    t = host->controlRead
+        (
+            dev,
+            USB_DEVICE_TO_HOST | USB_RECIPIENT_INTERFACE | USB_REQUEST_TYPE_STANDARD,
+            HID_GET_DESCRIPTOR,
+            0x2200,
+            0,
+            buf,
+            max_len_buf
+        );
+    if (len_rep_descr)
+        *len_rep_descr = max_len_buf;
+
+    return t;
+}
+
+/*
+ * HID Report Descriptor parser
+ */
+//bool USBHostGamepad::parseHidDescr()
+//{
+//    bool        ret = true;
+//    uint8_t*    buf;
+//    uint16_t    desclen = host->getLengthReportDescr();
+//    //allocate report descriptor's buffer
+//    buf = (uint8_t*)malloc(desclen);
+//    if (buf == NULL) {
+//        return false;
+//    }
+//    getReportDescriptor(dev, buf, desclen);
+//#if (DEBUG > 3)
+//    USB_DBG("HID REPORT DESCRIPTOR:\r\n");
+//    for (int i = 0; i < desclen; i++)
+//        printf("%02X ", buf[i]);
+//    printf("\r\n\r\n");
+//#endif
+//    if (buf[0] == 0x05 //Usage page
+//    && buf[1] == 0x01 //Generic Desktop
+//    && buf[2] == 0x09 //Usage
+//    ) {
+//        if (buf[3] == 0x04) {
+//            USB_DBG("GAMEPAD");
+//        }
+//        else
+//        if (buf[3] == 0x05) {
+//            USB_DBG("JOYSTICK");
+//        }
+//        else {
+//            ret = false;
+//        }
+//    }
+//    free(buf);
+//    return ret;
+//}
+//#endif
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostHID/USBHostGamepad.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHostHID/USBHostGamepad.h	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,126 @@
+/* mbed USBHost Gamepad driver sample
+ * Copyright (c) 2014 Yuuichi Akagawa
+ *
+ * modified from mbed USBHostMouse
+ *
+ * Copyright (c) 2014 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef USBHOSTGAMEPAD_H
+#define USBHOSTGAMEPAD_H
+
+#include "USBHostConf.h"
+
+//#if USBHOST_GAMEPAD
+
+#include "USBHost.h"
+//HID Class Request
+
+#define HID_GET_REPORT      0x01
+#define HID_GET_IDLE        0x02
+#define HID_GET_PROTOCOL    0x03
+#define HID_GET_DESCRIPTOR  0x06
+#define HID_SET_REPORT      0x09
+#define HID_SET_IDLE        0x0a
+#define HID_SET_PROTOCOL    0x0b
+
+/** 
+ * A class to communicate a USB MIDI device
+ */
+
+class USBHostGamepad :
+    public IUSBEnumerator
+{
+public:
+    /**
+     * Constructor
+     */
+    USBHostGamepad();
+
+    /**
+     * Try to connect a gamepad device
+     *
+     * @return true if connection was successful
+     */
+    bool    connect();
+
+    /**
+    * Check if a gamepad is connected
+    *
+    * @returns true if a gamepad is connected
+    */
+    bool    connected();
+
+    /**
+     * Attach a callback called when a gamepad event is received
+     *
+     * @param ptr function pointer
+     */
+    inline void attachEvent(void (*ptr) (uint8_t btnX, uint8_t btnY, uint8_t btnABCD, uint8_t btnSpecial))
+    {
+        if (ptr != NULL) {
+            onUpdate = ptr;
+        }
+    }
+
+    /**
+    * Request the HID report descriptor
+    *
+    * @param dev request the device descriptor on this device
+    * @param buf buffer to store the device descriptor
+    * @param max_len_buf maximum size of buf
+    * @param len_dev_descr pointer to store the length of the packet transferred
+    */
+    USB_TYPE    getReportDescriptor
+                (
+                    USBDeviceConnected*     dev,
+                    uint8_t*                buf,
+                    uint16_t                max_len_buf,
+                    uint16_t*               len_rep_descr = NULL
+                );
+protected:
+    //From IUSBEnumerator
+    virtual void    setVidPid(uint16_t vid, uint16_t pid);
+    virtual bool    parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol);  //Must return true if the interface should be parsed
+    virtual bool    useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir);                           //Must return true if the endpoint will be used
+
+private:
+    USBHost*                host;
+    USBDeviceConnected*     dev;
+    USBEndpoint*            int_in;
+
+    bool                    dev_connected;
+    bool                    gamepad_device_found;
+    int                     gamepad_intf;
+
+    uint8_t                 report[8];
+
+    void                    rxHandler();
+    void (*onUpdate) (uint8_t btnX, uint8_t btnY, uint8_t btnABCD, uint8_t btnSpecial);
+    int     report_id;
+    void    init();
+
+//    bool parseHidDescr();
+public:
+    uint8_t btnX;
+    uint8_t btnY;
+    uint8_t btnABCD;
+    uint8_t btnSpecial;
+};
+
+//#endif
+#endif
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostHID/USBHostKeyboard.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHostHID/USBHostKeyboard.cpp	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,163 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "USBHostKeyboard.h"
+
+#if USBHOST_KEYBOARD
+
+/*$off*/
+static uint8_t keymap[4][0x39] = { 
+    {   0,   0,   0,   0, 'a', 'b', 'c', 'd', 'e', 'f',
+      'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 
+      'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 
+      '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 
+      0x0A /*enter*/, 0x1B /*escape*/, 0x08 /*backspace*/, 0x09/*tab*/, 0x20/*space*/, '-', '=', '[', ']', '\\', 
+      '#', ';', '\'',  0, ',', '.', '/'
+    },
+
+    /* CTRL MODIFIER */
+    {   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+        0,   0,   0,   0,   0,   0,   0
+    },
+  
+    /* SHIFT MODIFIER */
+    {  0,    0,   0,   0, 'A', 'B', 'C', 'D', 'E', 'F',
+      'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+      'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+      '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
+       0,    0,   0,   0,   0,   0, '+', '{', '}', '|',
+      '~', ':', '"',   0, '<', '>', '?'
+    },
+
+    /* ALT MODIFIER */
+    {   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+        0,   0,   0,   0,   0,   0,   0
+    },
+};
+/*$on*/
+
+USBHostKeyboard::USBHostKeyboard() {
+    host = USBHost::getHostInst();
+    init();
+}
+
+void USBHostKeyboard::init() {
+    dev = NULL;
+    int_in = NULL;
+    report_id = 0;
+    onKey = NULL;
+    onKeyCode = NULL;
+    dev_connected = false;
+    keyboard_intf = -1;
+    keyboard_device_found = false;
+}
+
+bool USBHostKeyboard::connected() {
+    return dev_connected;
+}
+
+
+bool USBHostKeyboard::connect() {
+    
+    if (dev_connected) {
+        return true;
+    }
+    
+    for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
+        if ((dev = host->getDevice(i)) != NULL) {
+
+            if (host->enumerate(dev, this))
+                break;
+            
+            if (keyboard_device_found) {
+                int_in = dev->getEndpoint(keyboard_intf, INTERRUPT_ENDPOINT, IN);
+                
+                if (!int_in)
+                    break;
+                
+                USB_INFO("New Keyboard device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, keyboard_intf);
+                dev->setName("Keyboard", keyboard_intf);
+                host->registerDriver(dev, keyboard_intf, this, &USBHostKeyboard::init);
+                
+                int_in->attach(this, &USBHostKeyboard::rxHandler);
+                host->interruptRead(dev, int_in, report, int_in->getSize(), false);
+                
+                dev_connected = true;
+                return true;
+            }
+        }
+    }
+    init();
+    return false;
+}
+
+void USBHostKeyboard::rxHandler() {
+    int len = int_in->getLengthTransferred();
+    int index = (len == 9) ? 1 : 0;
+    int len_listen = int_in->getSize();
+    uint8_t key = 0;
+    if (len == 8 || len == 9) {
+        uint8_t modifier = (report[index] == 4) ? 3 : report[index];
+        len_listen = len;
+        key = keymap[modifier][report[index + 2]];
+        if (key && onKey) {
+            (*onKey)(key);
+        }
+        if ((report[index + 2] || modifier) && onKeyCode) {
+            (*onKeyCode)(report[index + 2], modifier);
+        }
+    }
+    if (dev && int_in)
+        host->interruptRead(dev, int_in, report, len_listen, false);
+}
+
+/*virtual*/ void USBHostKeyboard::setVidPid(uint16_t vid, uint16_t pid)
+{
+    // we don't check VID/PID for keyboard driver
+}
+
+/*virtual*/ bool USBHostKeyboard::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
+{
+    if ((keyboard_intf == -1) &&
+        (intf_class == HID_CLASS) &&
+        (intf_subclass == 0x01) &&
+        (intf_protocol == 0x01)) {
+        keyboard_intf = intf_nb;
+        return true;
+    }
+    return false;
+}
+
+/*virtual*/ bool USBHostKeyboard::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
+{
+    if (intf_nb == keyboard_intf) {
+        if (type == INTERRUPT_ENDPOINT && dir == IN) {
+            keyboard_device_found = true;
+            return true;
+        }
+    }
+    return false;
+}
+
+#endif
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostHID/USBHostKeyboard.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHostHID/USBHostKeyboard.h	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,102 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef USBHOSTKEYBOARD_H
+#define USBHOSTKEYBOARD_H
+
+#include "USBHostConf.h"
+
+#if USBHOST_KEYBOARD
+
+#include "USBHost.h"
+
+/** 
+ * A class to communicate a USB keyboard
+ */
+class USBHostKeyboard : public IUSBEnumerator {
+public:
+    
+    /**
+    * Constructor
+    */
+    USBHostKeyboard();
+
+    /**
+     * Try to connect a keyboard device
+     *
+     * @return true if connection was successful
+     */
+    bool connect();
+
+    /**
+    * Check if a keyboard is connected
+    *
+    * @returns true if a keyboard is connected
+    */
+    bool connected();
+
+    /**
+     * Attach a callback called when a keyboard event is received
+     *
+     * @param ptr function pointer
+     */
+    inline void attach(void (*ptr)(uint8_t key)) {
+        if (ptr != NULL) {
+            onKey = ptr;
+        }
+    }
+
+    /**
+     * Attach a callback called when a keyboard event is received
+     *
+     * @param ptr function pointer
+     */
+    inline void attach(void (*ptr)(uint8_t keyCode, uint8_t modifier)) {
+        if (ptr != NULL) {
+            onKeyCode = ptr;
+        }
+    }
+
+protected:
+    //From IUSBEnumerator
+    virtual void setVidPid(uint16_t vid, uint16_t pid);
+    virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
+    virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
+
+private:
+    USBHost * host;
+    USBDeviceConnected * dev;
+    USBEndpoint * int_in;
+    uint8_t report[9];
+    int keyboard_intf;
+    bool keyboard_device_found;
+    
+    bool dev_connected;
+
+    void rxHandler();
+
+    void (*onKey)(uint8_t key);
+    void (*onKeyCode)(uint8_t key, uint8_t modifier);
+
+    int report_id;
+    
+    void init();
+
+};
+
+#endif
+
+#endif
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostHID/USBHostMouse.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHostHID/USBHostMouse.cpp	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,191 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "USBHostMouse.h"
+
+#if USBHOST_MOUSE
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+USBHostMouse::USBHostMouse()
+{
+    host = USBHost::getHostInst();
+    init();
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void USBHostMouse::init()
+{
+    dev = NULL;
+    int_in = NULL;
+    onUpdate = NULL;
+    onButtonUpdate = NULL;
+    onXUpdate = NULL;
+    onYUpdate = NULL;
+    onZUpdate = NULL;
+    report_id = 0;
+    dev_connected = false;
+    mouse_device_found = false;
+    mouse_intf = -1;
+
+    buttons = 0;
+    x = 0;
+    y = 0;
+    z = 0;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+bool USBHostMouse::connected()
+{
+    return dev_connected;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+bool USBHostMouse::connect()
+{
+    int len_listen;
+
+    if (dev_connected) {
+        return true;
+    }
+
+    for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
+        if ((dev = host->getDevice(i)) != NULL) {
+            if (host->enumerate(dev, this))
+                break;
+
+            if (mouse_device_found) {
+                int_in = dev->getEndpoint(mouse_intf, INTERRUPT_ENDPOINT, IN);
+                if (!int_in)
+                    break;
+
+                USB_INFO
+                (
+                    "New Mouse device: VID:%04x PID:%04x [dev: %p - intf: %d]",
+                    dev->getVid(),
+                    dev->getPid(),
+                    dev,
+                    mouse_intf
+                );
+                dev->setName("Mouse", mouse_intf);
+                host->registerDriver(dev, mouse_intf, this, &USBHostMouse::init);
+
+                int_in->attach(this, &USBHostMouse::rxHandler);
+                len_listen = int_in->getSize();
+                if (len_listen > sizeof(report)) {
+                    len_listen = sizeof(report);
+                }
+
+                host->interruptRead(dev, int_in, report, len_listen, false);
+
+                dev_connected = true;
+                return true;
+            }
+        }
+    }
+
+    init();
+    return false;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void USBHostMouse::rxHandler()
+{
+    int len_listen = int_in->getSize();
+
+    if (onUpdate) {
+        (*onUpdate) (report[0] & 0x07, report[1], report[2], report[3]);
+    }
+
+    if (onButtonUpdate && (buttons != (report[0] & 0x07))) {
+        (*onButtonUpdate) (report[0] & 0x07);
+    }
+
+    if (onXUpdate && (x != report[1])) {
+        (*onXUpdate) (report[1]);
+    }
+
+    if (onYUpdate && (y != report[2])) {
+        (*onYUpdate) (report[2]);
+    }
+
+    if (onZUpdate && (z != report[3])) {
+        (*onZUpdate) (report[3]);
+    }
+
+    // update mouse state
+    buttons = report[0] & 0x07;
+    x = report[1];
+    y = report[2];
+    z = report[3];
+
+    if (dev)
+        host->interruptRead(dev, int_in, report, len_listen, false);
+}
+
+/*virtual*/
+void USBHostMouse::setVidPid(uint16_t vid, uint16_t pid)
+{
+    // we don't check VID/PID for mouse driver
+}
+
+/*virtual*/
+bool USBHostMouse::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol)    //Must return true if the interface should be parsed
+{
+    if ((mouse_intf == -1) && (intf_class == HID_CLASS) && (intf_subclass == 0x01) && (intf_protocol == 0x02)) {
+        mouse_intf = intf_nb;
+        return true;
+    }
+
+    return false;
+}
+
+/*virtual*/
+bool USBHostMouse::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
+{
+    if (intf_nb == mouse_intf) {
+        if (type == INTERRUPT_ENDPOINT && dir == IN) {
+            mouse_device_found = true;
+            return true;
+        }
+    }
+
+    return false;
+}
+#endif
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostHID/USBHostMouse.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHostHID/USBHostMouse.h	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,139 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef USBHOSTMOUSE_H
+#define USBHOSTMOUSE_H
+
+#include "USBHostConf.h"
+
+#if USBHOST_MOUSE
+
+#include "USBHost.h"
+
+/** 
+ * A class to communicate a USB mouse
+ */
+class USBHostMouse : public IUSBEnumerator {
+public:
+
+    /**
+    * Constructor
+    */
+    USBHostMouse();
+
+    /**
+     * Try to connect a mouse device
+     *
+     * @return true if connection was successful
+     */
+    bool connect();
+
+    /**
+    * Check if a mouse is connected
+    *
+    * @returns true if a mouse is connected
+    */
+    bool connected();
+
+    /**
+     * Attach a callback called when a mouse event is received
+     *
+     * @param ptr function pointer
+     */
+    inline void attachEvent(void (*ptr)(uint8_t buttons, int8_t x, int8_t y, int8_t z)) {
+        if (ptr != NULL) {
+            onUpdate = ptr;
+        }
+    }
+    
+    /**
+     * Attach a callback called when the button state changes
+     *
+     * @param ptr function pointer
+     */
+    inline void attachButtonEvent(void (*ptr)(uint8_t buttons)) {
+        if (ptr != NULL) {
+            onButtonUpdate = ptr;
+        }
+    }
+    
+    /**
+     * Attach a callback called when the X axis value changes
+     *
+     * @param ptr function pointer
+     */
+    inline void attachXEvent(void (*ptr)(int8_t x)) {
+        if (ptr != NULL) {
+            onXUpdate = ptr;
+        }
+    }
+    
+    /**
+     * Attach a callback called when the Y axis value changes
+     *
+     * @param ptr function pointer
+     */
+    inline void attachYEvent(void (*ptr)(int8_t y)) {
+        if (ptr != NULL) {
+            onYUpdate = ptr;
+        }
+    }
+    
+    /**
+     * Attach a callback called when the Z axis value changes (scrolling)
+     *
+     * @param ptr function pointer
+     */
+    inline void attachZEvent(void (*ptr)(int8_t z)) {
+        if (ptr != NULL) {
+            onZUpdate = ptr;
+        }
+    }
+
+protected:
+    //From IUSBEnumerator
+    virtual void setVidPid(uint16_t vid, uint16_t pid);
+    virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
+    virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
+
+private:
+    USBHost * host;
+    USBDeviceConnected * dev;
+    USBEndpoint * int_in;
+    uint8_t report[4];
+    
+    bool dev_connected;
+    bool mouse_device_found;
+    int mouse_intf;
+
+    uint8_t buttons;
+    int8_t x;
+    int8_t y;
+    int8_t z;
+
+    void rxHandler();
+    void (*onUpdate)(uint8_t buttons, int8_t x, int8_t y, int8_t z);
+    void (*onButtonUpdate)(uint8_t buttons);
+    void (*onXUpdate)(int8_t x);
+    void (*onYUpdate)(int8_t y);
+    void (*onZUpdate)(int8_t z);
+    int report_id;
+    void init();
+};
+
+#endif
+
+#endif
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostMSD/USBHostMSD.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHostMSD/USBHostMSD.cpp	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,356 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "USBHostMSD.h"
+
+#if USBHOST_MSD
+
+#include "dbg.h"
+
+#define CBW_SIGNATURE   0x43425355
+#define CSW_SIGNATURE   0x53425355
+
+#define DEVICE_TO_HOST  0x80
+#define HOST_TO_DEVICE  0x00
+
+#define GET_MAX_LUN             (0xFE)
+#define BO_MASS_STORAGE_RESET   (0xFF)
+
+USBHostMSD::USBHostMSD(const char * rootdir) : FATFileSystem(rootdir)
+{
+    host = USBHost::getHostInst();
+    init();
+}
+
+void USBHostMSD::init() {
+    dev_connected = false;
+    dev = NULL;
+    bulk_in = NULL;
+    bulk_out = NULL;
+    dev_connected = false;
+    blockSize = 0;
+    blockCount = 0;
+    msd_intf = -1;
+    msd_device_found = false;
+    disk_init = false;
+    dev_connected = false;
+    nb_ep = 0;
+}
+
+
+bool USBHostMSD::connected()
+{
+    return dev_connected;
+}
+
+bool USBHostMSD::connect()
+{
+
+    if (dev_connected) {
+        return true;
+    }
+
+    for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
+        if ((dev = host->getDevice(i)) != NULL) {
+            
+            USB_DBG("Trying to connect MSD device\r\n");
+            
+            if(host->enumerate(dev, this))
+                break;
+
+            if (msd_device_found) {
+                bulk_in = dev->getEndpoint(msd_intf, BULK_ENDPOINT, IN);
+                bulk_out = dev->getEndpoint(msd_intf, BULK_ENDPOINT, OUT);
+                
+                if (!bulk_in || !bulk_out)
+                    continue;
+                
+                USB_INFO("New MSD device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, msd_intf);
+                dev->setName("MSD", msd_intf);
+                host->registerDriver(dev, msd_intf, this, &USBHostMSD::init);
+
+                dev_connected = true;
+                return true;
+            }
+        } //if()
+    } //for()
+    init();
+    return false;
+}
+
+/*virtual*/ void USBHostMSD::setVidPid(uint16_t vid, uint16_t pid)
+{
+    // we don't check VID/PID for MSD driver
+}
+
+/*virtual*/ bool USBHostMSD::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
+{
+    if ((msd_intf == -1) &&
+        (intf_class == MSD_CLASS) &&
+        (intf_subclass == 0x06) &&
+        (intf_protocol == 0x50)) {
+        msd_intf = intf_nb;
+        return true;
+    }
+    return false;
+}
+
+/*virtual*/ bool USBHostMSD::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
+{
+    if (intf_nb == msd_intf) {
+        if (type == BULK_ENDPOINT) {
+            nb_ep++;
+            if (nb_ep == 2)
+                msd_device_found = true;
+            return true;
+        }
+    }
+    return false;
+}
+
+
+int USBHostMSD::testUnitReady() {
+    USB_DBG("Test unit ready");
+    return SCSITransfer(NULL, 6, DEVICE_TO_HOST, 0, 0);
+}
+
+
+int USBHostMSD::readCapacity() {
+    USB_DBG("Read capacity");
+    uint8_t cmd[10] = {0x25,0,0,0,0,0,0,0,0,0};
+    uint8_t result[8];
+    int status = SCSITransfer(cmd, 10, DEVICE_TO_HOST, result, 8);
+    if (status == 0) {
+        blockCount = (result[0] << 24) | (result[1] << 16) | (result[2] << 8) | result[3];
+        blockSize = (result[4] << 24) | (result[5] << 16) | (result[6] << 8) | result[7];
+        USB_INFO("MSD [dev: %p] - blockCount: %lld, blockSize: %d, Capacity: %lld\r\n", dev, blockCount, blockSize, blockCount*blockSize);
+    }
+    return status;
+}
+
+
+int USBHostMSD::SCSIRequestSense() {
+    USB_DBG("Request sense");
+    uint8_t cmd[6] = {0x03,0,0,0,18,0};
+    uint8_t result[18];
+    int status = SCSITransfer(cmd, 6, DEVICE_TO_HOST, result, 18);
+    return status;
+}
+
+
+int USBHostMSD::inquiry(uint8_t lun, uint8_t page_code) {
+    USB_DBG("Inquiry");
+    uint8_t evpd = (page_code == 0) ? 0 : 1;
+    uint8_t cmd[6] = {0x12, uint8_t((lun << 5) | evpd), page_code, 0, 36, 0};
+    uint8_t result[36];
+    int status = SCSITransfer(cmd, 6, DEVICE_TO_HOST, result, 36);
+    if (status == 0) {
+        char vid_pid[17];
+        memcpy(vid_pid, &result[8], 8);
+        vid_pid[8] = 0;
+        USB_INFO("MSD [dev: %p] - Vendor ID: %s", dev, vid_pid);
+
+        memcpy(vid_pid, &result[16], 16);
+        vid_pid[16] = 0;
+        USB_INFO("MSD [dev: %p] - Product ID: %s", dev, vid_pid);
+
+        memcpy(vid_pid, &result[32], 4);
+        vid_pid[4] = 0;
+        USB_INFO("MSD [dev: %p] - Product rev: %s", dev, vid_pid);
+    }
+    return status;
+}
+
+int USBHostMSD::checkResult(uint8_t res, USBEndpoint * ep) {
+    // if ep stalled: send clear feature
+    if (res == USB_TYPE_STALL_ERROR) {
+        res = host->controlWrite(   dev,
+                                    USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD,
+                                    CLEAR_FEATURE,
+                                    0, ep->getAddress(), NULL, 0);
+        // set state to IDLE if clear feature successful
+        if (res == USB_TYPE_OK) {
+            ep->setState(USB_TYPE_IDLE);
+        }
+    }
+
+    if (res != USB_TYPE_OK)
+        return -1;
+
+    return 0;
+}
+
+
+int USBHostMSD::SCSITransfer(uint8_t * cmd, uint8_t cmd_len, int flags, uint8_t * data, uint32_t transfer_len) {
+
+    int res = 0;
+
+    cbw.Signature = CBW_SIGNATURE;
+    cbw.Tag = 0;
+    cbw.DataLength = transfer_len;
+    cbw.Flags = flags;
+    cbw.LUN = 0;
+    cbw.CBLength = cmd_len;
+    memset(cbw.CB,0,sizeof(cbw.CB));
+    if (cmd) {
+        memcpy(cbw.CB,cmd,cmd_len);
+    }
+
+    // send the cbw
+    USB_DBG("Send CBW");
+    res = host->bulkWrite(dev, bulk_out,(uint8_t *)&cbw, 31);
+    if (checkResult(res, bulk_out))
+        return -1;
+
+    // data stage if needed
+    if (data) {
+        USB_DBG("data stage");
+        if (flags == HOST_TO_DEVICE) {
+            
+            res = host->bulkWrite(dev, bulk_out, data, transfer_len);
+            if (checkResult(res, bulk_out))
+                return -1;
+
+        } else if (flags == DEVICE_TO_HOST) {
+
+            res = host->bulkRead(dev, bulk_in, data, transfer_len);
+            if (checkResult(res, bulk_in))
+                return -1;
+        }
+    }
+
+    // status stage
+    csw.Signature = 0;
+    USB_DBG("Read CSW");
+    res = host->bulkRead(dev, bulk_in,(uint8_t *)&csw, 13);
+    if (checkResult(res, bulk_in))
+        return -1;
+
+    if (csw.Signature != CSW_SIGNATURE) {
+        return -1;
+    }
+    
+    USB_DBG("recv csw: status: %d", csw.Status);
+
+    // ModeSense?
+    if ((csw.Status == 1) && (cmd[0] != 0x03)) {
+        USB_DBG("request mode sense");
+        return SCSIRequestSense();
+    }
+    
+    // perform reset recovery
+    if ((csw.Status == 2) && (cmd[0] != 0x03)) {
+        
+        // send Bulk-Only Mass Storage Reset request
+        res = host->controlWrite(   dev,
+                                    USB_RECIPIENT_INTERFACE | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS,
+                                    BO_MASS_STORAGE_RESET,
+                                    0, msd_intf, NULL, 0);
+        
+        // unstall both endpoints
+        res = host->controlWrite(   dev,
+                                    USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD,
+                                    CLEAR_FEATURE,
+                                    0, bulk_in->getAddress(), NULL, 0);
+        
+        res = host->controlWrite(   dev,
+                                    USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD,
+                                    CLEAR_FEATURE,
+                                    0, bulk_out->getAddress(), NULL, 0);
+        
+    }
+
+    return csw.Status;
+}
+
+
+int USBHostMSD::dataTransfer(uint8_t * buf, uint32_t block, uint8_t nbBlock, int direction) {
+    uint8_t cmd[10];
+    memset(cmd,0,10);
+    cmd[0] = (direction == DEVICE_TO_HOST) ? 0x28 : 0x2A;
+
+    cmd[2] = (block >> 24) & 0xff;
+    cmd[3] = (block >> 16) & 0xff;
+    cmd[4] = (block >> 8) & 0xff;
+    cmd[5] =  block & 0xff;
+
+    cmd[7] = (nbBlock >> 8) & 0xff;
+    cmd[8] = nbBlock & 0xff;
+
+    return SCSITransfer(cmd, 10, direction, buf, blockSize*nbBlock);
+}
+
+int USBHostMSD::getMaxLun() {
+    uint8_t buf[1], res;
+    res = host->controlRead(    dev, USB_RECIPIENT_INTERFACE | USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS,
+                                0xfe, 0, msd_intf, buf, 1);
+    USB_DBG("max lun: %d", buf[0]);
+    return res;
+}
+
+int USBHostMSD::disk_initialize() {
+    USB_DBG("FILESYSTEM: init");
+    /* U16 */int i, timeout = 10;
+    
+    getMaxLun();
+    
+    for (i = 0; i < timeout; i++) {
+        wait_ms(100); //Thread::wait(100);
+        if (!testUnitReady())
+            break;
+    }
+    
+    if (i == timeout) {
+        disk_init = false;
+        return -1;
+    }
+    
+    inquiry(0, 0);
+    disk_init = 1;
+    return readCapacity();
+}
+
+int USBHostMSD::disk_write(const uint8_t *buffer, uint32_t sector, uint32_t count) {
+    USB_DBG("FILESYSTEM: write sector: %lld, count: %d", sector, count);
+    if (!disk_init) {
+        disk_initialize();
+    }
+    if (!disk_init)
+        return -1;
+    return dataTransfer((uint8_t *)buffer, sector, count, HOST_TO_DEVICE);
+}
+
+int USBHostMSD::disk_read(uint8_t * buffer, uint32_t sector, uint32_t count) {
+    USB_DBG("FILESYSTEM: read sector: %lld, count: %d", sector, count);
+    if (!disk_init) {
+        disk_initialize();
+    }
+    if (!disk_init)
+        return -1;
+    return dataTransfer((uint8_t *)buffer, sector, count, DEVICE_TO_HOST);
+}
+
+uint32_t USBHostMSD::disk_sectors() {
+    USB_DBG("FILESYSTEM: sectors");
+    if (!disk_init) {
+        disk_initialize();
+    }
+    if (!disk_init)
+        return 0;
+    return blockCount;
+}
+
+#endif
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostMSD/USBHostMSD.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHostMSD/USBHostMSD.h	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,119 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef USBHOSTMSD_H
+#define USBHOSTMSD_H
+
+#include "USBHostConf.h"
+
+#if USBHOST_MSD
+
+#include "USBHost.h"
+#include "FATFileSystem.h"
+
+/** 
+ * A class to communicate a USB flash disk
+ */
+class USBHostMSD : public IUSBEnumerator, public FATFileSystem {
+public:
+    /**
+    * Constructor
+    *
+    * @param rootdir mount name
+    */
+    USBHostMSD(const char * rootdir);
+
+    /**
+    * Check if a MSD device is connected
+    *
+    * @return true if a MSD device is connected
+    */
+    bool connected();
+
+    /**
+     * Try to connect to a MSD device
+     *
+     * @return true if connection was successful
+     */
+    bool connect();
+
+protected:
+    //From IUSBEnumerator
+    virtual void setVidPid(uint16_t vid, uint16_t pid);
+    virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
+    virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
+
+    // From FATFileSystem
+    virtual int disk_initialize();
+    virtual int disk_status() {return 0;}
+    virtual int disk_read(uint8_t * buffer, uint32_t sector, uint32_t count);
+    virtual int disk_write(const uint8_t * buffer, uint32_t sector, uint32_t count);
+    virtual int disk_sync() {return 0;}
+    virtual uint32_t disk_sectors();
+
+private:
+    USBHost * host;
+    USBDeviceConnected * dev;
+    bool dev_connected;
+    USBEndpoint * bulk_in;
+    USBEndpoint * bulk_out;
+    uint8_t nb_ep;
+
+    // Bulk-only CBW
+    typedef struct {
+        uint32_t Signature;
+        uint32_t Tag;
+        uint32_t DataLength;
+        uint8_t  Flags;
+        uint8_t  LUN;
+        uint8_t  CBLength;
+        uint8_t  CB[16];
+    } PACKED CBW;
+
+    // Bulk-only CSW
+    typedef struct {
+        uint32_t Signature;
+        uint32_t Tag;
+        uint32_t DataResidue;
+        uint8_t  Status;
+    } PACKED CSW;
+
+    CBW cbw;
+    CSW csw;
+
+    int SCSITransfer(uint8_t * cmd, uint8_t cmd_len, int flags, uint8_t * data, uint32_t transfer_len);
+    int testUnitReady();
+    int readCapacity();
+    int inquiry(uint8_t lun, uint8_t page_code);
+    int SCSIRequestSense();
+    int dataTransfer(uint8_t * buf, uint32_t block, uint8_t nbBlock, int direction);
+    int checkResult(uint8_t res, USBEndpoint * ep);
+    int getMaxLun();
+
+    int blockSize;
+    uint64_t blockCount;
+
+    int msd_intf;
+    bool msd_device_found;
+    bool disk_init;
+    
+    void init();
+
+};
+
+#endif
+
+#endif
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostRSSI/USBHostRSSI.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHostRSSI/USBHostRSSI.cpp	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,193 @@
+#include "USBHostRSSI.h"
+
+USBHostRSSI::USBHostRSSI()
+{
+    host = USBHost::getHostInst();
+    init();
+}
+
+void USBHostRSSI::init()
+{
+    dev = NULL;
+    int_in = NULL;
+    onUpdate = NULL;
+    dev_connected = false;
+    bluetooth_device_found = false;
+    bluetooth_intf = -1;
+    seq = 0;
+    
+}
+
+bool USBHostRSSI::connected() {
+    return dev_connected;
+}
+
+bool USBHostRSSI::connect() {
+
+    if (dev_connected) {
+        return true;
+    }
+    
+    for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
+        if ((dev = host->getDevice(i)) != NULL) {
+            if(host->enumerate(dev, this)) {
+                break;
+            }
+            if (bluetooth_device_found) {
+                int_in = dev->getEndpoint(bluetooth_intf, INTERRUPT_ENDPOINT, IN);
+                USB_DBG("int_in=%p", int_in);
+                if (!int_in) {
+                    break;
+                }
+                USB_INFO("New Bluetooth device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, bluetooth_intf);
+                int_in->attach(this, &USBHostRSSI::rxHandler);
+                int rc = host->interruptRead(dev, int_in, int_buf, sizeof(int_buf), false);
+                USB_TEST_ASSERT(rc != USB_TYPE_ERROR);
+                rc = cmdSend(HCI_OP_RESET);
+                USB_TEST_ASSERT(rc == USB_TYPE_OK);
+                dev_connected = true;
+                return true;
+            }
+        }
+    }
+    init();
+    return false;
+}
+
+void USBHostRSSI::rxHandler() {
+    event(int_buf, int_in->getLengthTransferred());
+    if (dev) {
+        host->interruptRead(dev, int_in, int_buf, sizeof(int_buf), false);
+    }
+}
+
+/*virtual*/ void USBHostRSSI::setVidPid(uint16_t vid, uint16_t pid)
+{
+    USB_DBG("vid:%04x pid:%04x", vid, pid);
+    // we don't check VID/PID for mouse driver
+}
+
+/*virtual*/ bool USBHostRSSI::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
+{
+    USB_DBG("intf: %d class: %02x %02x %02x", intf_nb, intf_class, intf_subclass, intf_protocol);
+    if (bluetooth_intf == -1 && intf_class == 0xe0) {
+        bluetooth_intf = intf_nb;
+        return true;
+    }
+    return false;
+}
+
+/*virtual*/ bool USBHostRSSI::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
+{
+    USB_DBG("intf_nb=%d type=%d dir=%d", intf_nb, type, dir);
+
+    if (intf_nb == bluetooth_intf) {
+        if (type == INTERRUPT_ENDPOINT && dir == IN) {
+            bluetooth_device_found = true;
+            return true;
+        }
+    }
+    return false;
+}
+
+void USBHostRSSI::event(uint8_t* data, int len) {
+    CTASSERT(sizeof(BD_ADDR) == 6);
+    CTASSERT(sizeof(inquiry_with_rssi_info) == 14);
+    inquiry_with_rssi_info* info;
+    int max_period_length = 25;
+    int min_period_length = 20;
+    int inquiry_length = 15;
+    USB_TYPE rc;
+    if (len > 0) {
+        USB_DBG_HEX(data, len);
+        hci_event* event = reinterpret_cast<hci_event*>(data);
+        switch(event->evt) {
+            case HCI_EV_CMD_COMPLETE:
+                switch(event->c.op) {
+                    case HCI_OP_RESET:
+                        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", 
+                                            max_period_length, min_period_length, 0x33, 0x8B, 0x9E, inquiry_length, 0);
+                        USB_TEST_ASSERT(rc == USB_TYPE_OK);
+                        break;
+                    default:
+                        break;
+                }
+                break;
+            case HCI_EV_INQUIRY_RESULT_WITH_RSSI:
+                //USB_DBG_HEX(buf, r);
+                info = reinterpret_cast<inquiry_with_rssi_info*>(event->c.data);
+                if (onUpdate) {
+                    (*onUpdate)(info);
+                }
+                break;
+            default:
+                break;
+        }        
+    }
+}
+
+USB_TYPE USBHostRSSI::cmdSend(uint16_t op)
+{
+   return cmdSendSub(op, NULL, 0);
+}
+
+USB_TYPE USBHostRSSI::cmdSend(uint16_t op, const char* fmt, ...) 
+{   
+    va_list vl;
+    va_start(vl, fmt);
+    uint8_t buf[255];
+    int pos = 0;
+    char* name;
+    int name_len;
+    uint16_t h;
+    BD_ADDR* bdaddr;
+    for(int i = 0; fmt[i]; i++) {
+        switch(fmt[i]) {
+            case 's':
+                name = va_arg(vl, char*);
+                name_len = strlen(name)+1;
+                memcpy(buf+pos, name, name_len);
+                pos += name_len;
+                break;
+            case 'B':
+                buf[pos++] = va_arg(vl, int);
+                break;
+            case 'H':
+                h = va_arg(vl, int);
+                buf[pos++] = h;
+                buf[pos++] = h>>8;
+                break;
+            case 'A':
+                bdaddr = va_arg(vl, BD_ADDR*);
+                memcpy(buf+pos, bdaddr, 6);
+                pos += 6;
+                break;
+            default:
+                USB_DBG("op=%04X fmt=%s i=%d", op, fmt, i);
+                break;
+        }
+    }
+    return cmdSendSub(op, buf, pos);
+}
+
+USB_TYPE USBHostRSSI::cmdSendSub(uint16_t op, const uint8_t* data, int size)
+{
+    uint8_t* buf = new uint8_t[size+3];
+    buf[0] = op;
+    buf[1] = op>>8;
+    buf[2] = size;
+    if (data) {
+        memcpy(buf+3, data, size);
+    }
+    USB_TYPE rc = host->controlWrite(dev, USB_REQUEST_TYPE_CLASS, 0, 0, 0, buf, size+3);
+    USB_TEST_ASSERT(rc == USB_TYPE_OK);
+    delete[] buf;
+    return rc;
+}
diff -r 000000000000 -r 458bf947f46f USBHost-STM32F4/USBHostRSSI/USBHostRSSI.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost-STM32F4/USBHostRSSI/USBHostRSSI.h	Tue Feb 19 21:32:56 2019 +0000
@@ -0,0 +1,145 @@
+// Simple USBHost Bluetooth RSSI for FRDM-KL46Z
+#pragma once
+#include "USBHost.h"
+#include <stdarg.h>
+
+#define HCI_OP_INQUIRY               0x0401
+#define HCI_OP_INQUIRY_CANCEL        0x0402
+#define HCI_OP_PERIODIC_INQUIRY      0x0403
+#define HCI_OP_EXIT_PERIODIC_INQUIRY 0x0404
+#define HCI_OP_REMOTE_NAME_REQ       0x0419
+#define HCI_OP_RESET                 0x0c03
+#define HCI_OP_WRITE_LOCAL_NAME      0x0c13
+#define HCI_OP_WRITE_SCAN_ENABLE     0x0c1a
+#define HCI_OP_WRITE_CLASS_OF_DEV    0x0c24
+#define HCI_OP_WRITE_INQUIRY_MODE    0x0c45
+#define HCI_OP_READ_EXTENDED_INQUIRY_RESPONSE  0x0c51
+#define HCI_OP_WRITE_EXTENDED_INQUIRY_RESPONSE 0x0c52
+#define HCI_OP_READ_BD_ADDR          0x1009
+
+#define HCI_EV_INQUIRY_COMPLETE         0x01
+#define HCI_EV_INQUIRY_RESULT           0x02
+#define HCI_EV_REMOTE_NAME              0x07
+#define HCI_EV_CMD_COMPLETE             0x0e
+#define HCI_EV_CMD_STATUS               0x0f
+#define HCI_EV_INQUIRY_RESULT_WITH_RSSI 0x22
+#define HCI_EV_EXTENDED_INQUIRY_RESULT  0x2f
+
+#pragma pack(push,1)
+struct BD_ADDR {
+    uint8_t addr[6];
+    void set(char* s) {
+        char* p = s;
+        for(int i = 5; i >= 0; i--) {
+            addr[i] =  strtol(p, &p, 16);
+            if (*p == ':') {
+                p++;
+            }
+        }
+    }
+    void str(char* buf, size_t size) {
+        snprintf(buf, size, "%02X:%02X:%02X:%02X:%02X:%02X", addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]);
+    }
+    void str_mask(char* buf, size_t size) {
+        snprintf(buf, size, "%02X:%02X:%02X:xx:xx:xx", addr[5], addr[4], addr[3]);
+    }
+    bool eq(BD_ADDR* a) {
+        return memcmp(addr, a->addr, 6) == 0;
+    }
+    bool eq_vendor(BD_ADDR* a) {
+        return memcmp(addr+3, a->addr+3, 3) == 0;
+    }
+};
+
+struct inquiry_info {
+    BD_ADDR bdaddr;
+    uint8_t page_scan_repetition_mode;
+    uint8_t reserved[2];
+    uint8_t dev_class[3];
+    uint16_t clock_offset;
+};
+
+struct inquiry_with_rssi_info {       // offset
+    BD_ADDR bdaddr;                   // +0
+    uint8_t page_scan_repetition_mode;// +6
+    uint8_t reserved[1];              // +7
+    uint8_t class_of_device[3];       // +8
+    uint16_t clock_offset;            // +11
+    int8_t rssi;                      // +13
+};                                    // +14
+
+struct extended_inquiry_info {
+    BD_ADDR bdaddr;
+    uint8_t page_scan_repetition_mode;
+    uint8_t reserved[1];
+    uint8_t class_of_device[3];
+    uint16_t clock_offset;
+    int8_t rssi;
+    uint8_t extended_inquiry_response[240];
+};
+
+struct hci_event {
+    uint8_t evt;
+    uint8_t len;
+    uint8_t status;
+    union {
+        uint16_t op;
+        uint8_t data[2];
+    } c;
+};
+#pragma pack(pop)
+
+class USBHostRSSI : public IUSBEnumerator {
+public:
+
+    /**
+    * Constructor
+    */    
+    USBHostRSSI();
+
+    /**
+     * Try to connect a BT device
+     *
+     * @return true if connection was successful
+     */
+    bool connect();
+
+    /**
+    * Check if a mouse is connected
+    *
+    * @returns true if a BT is connected
+    */
+    bool connected();
+
+    void attachEvent(void (*ptr)(inquiry_with_rssi_info* info)) {
+        if (ptr != NULL) {
+            onUpdate = ptr;
+        }
+    }
+    //Report* report;
+
+protected:
+    //From IUSBEnumerator
+    virtual void setVidPid(uint16_t vid, uint16_t pid);
+    virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
+    virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
+
+private:
+    USBHost * host;
+    USBDeviceConnected * dev;
+    USBEndpoint * int_in;
+    bool dev_connected;
+    bool bluetooth_device_found;
+    int bluetooth_intf;
+
+    void rxHandler();
+    void (*onUpdate)(inquiry_with_rssi_info* info);
+    uint8_t int_buf[64];
+    int seq;
+    void event(uint8_t* data, int size);
+    USB_TYPE cmdSend(uint16_t op);
+    USB_TYPE cmdSend(uint16_t op, const char* fmt, ...);
+    USB_TYPE cmdSendSub(uint16_t op, const uint8_t* data, int size);
+    void init();
+};
+