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

Dependencies:   FATFileSystem

Dependents:   F401RE-BTstack_example F401RE-USBHostMSD_HelloWorld

Fork of KL46Z-USBHost by Norimasa Okamoto

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

Platforms

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

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

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

Examples

Import programF446RE-USBHostMouse_HelloWorld

USBHostMouse Hello World for ST-Nucleo-F446RE

Import programF401RE-USBHostMSD_HelloWorld

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

Import programF401RE-USBHostC270_example

Simple USBHost WebCam test program

Import programK64F_USBHostC270_example

Simple USBHost C270 example

Import programF401RE-BTstack_example

BTstack for Nucleo F401RE/FRDM-KL46Z example program

Import programUSBHostRSSI_example

Bluetooth device discovery example program.

Import programKL46Z-USBHostGPS_HelloWorld

Simple USBHost GPS Dongle Receiver for FRDM-KL46Z test program

Files at this revision

API Documentation at this revision

Comitter:
va009039
Date:
Tue Jun 10 13:38:41 2014 +0900
Parent:
12:b91fdea8c0a7
Child:
14:b167f2b97cb7
Commit message:
add USBHostC270

Changed in this revision

USBHost/USBHALHost2_F401RE.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHALHost_F401RE.cpp Show annotated file Show diff for this revision Revisions of this file
USBHostC270/BaseUvc.cpp Show annotated file Show diff for this revision Revisions of this file
USBHostC270/BaseUvc.h Show annotated file Show diff for this revision Revisions of this file
USBHostC270/CamInfo.cpp Show annotated file Show diff for this revision Revisions of this file
USBHostC270/USBHostCam.cpp Show annotated file Show diff for this revision Revisions of this file
USBHostC270/USBHostCam.h Show annotated file Show diff for this revision Revisions of this file
USBHostC270/decodeMJPEG.cpp Show annotated file Show diff for this revision Revisions of this file
USBHostC270/decodeMJPEG.h Show annotated file Show diff for this revision Revisions of this file
USBHostGPS/USBHostGPS.cpp Show annotated file Show diff for this revision Revisions of this file
USBHostGPS/USBHostGPS.h Show annotated file Show diff for this revision Revisions of this file
USBHostGPS/decodeNMEA.cpp Show annotated file Show diff for this revision Revisions of this file
USBHostGPS/decodeNMEA.h Show annotated file Show diff for this revision Revisions of this file
USBHostHID/USBHostKeyboard.cpp Show annotated file Show diff for this revision Revisions of this file
USBHostHID/USBHostKeyboard.h Show annotated file Show diff for this revision Revisions of this file
USBHostHID/USBHostMouse.cpp Show annotated file Show diff for this revision Revisions of this file
USBHostHID/USBHostMouse.h Show annotated file Show diff for this revision Revisions of this file
USBHostRSSI/USBHostRSSI.cpp Show annotated file Show diff for this revision Revisions of this file
USBHostRSSI/USBHostRSSI.h Show annotated file Show diff for this revision Revisions of this file
--- a/USBHost/USBHALHost2_F401RE.cpp	Mon Jun 09 09:01:10 2014 +0000
+++ b/USBHost/USBHALHost2_F401RE.cpp	Tue Jun 10 13:38:41 2014 +0900
@@ -199,6 +199,12 @@
       USB_HC_Halt(hhcd->Instance, chnum); 
       __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_NAK);
     }
+    else if(hhcd->hc[chnum].ep_type == EP_TYPE_ISOC)
+    {
+      USBx_HC(chnum)->HCCHAR |= USB_OTG_HCCHAR_ODDFRM;
+      hhcd->hc[chnum].urb_state = URB_DONE; 
+      HAL_HCD_HC_NotifyURBChange_Callback(hhcd, chnum, hhcd->hc[chnum].urb_state);
+    }
     hhcd->hc[chnum].toggle_in ^= 1;
     
   }
--- a/USBHost/USBHALHost_F401RE.cpp	Mon Jun 09 09:01:10 2014 +0000
+++ b/USBHost/USBHALHost_F401RE.cpp	Tue Jun 10 13:38:41 2014 +0900
@@ -409,24 +409,17 @@
 }
 
 int USBHALHost::token_iso_in(USBEndpoint* ep, uint8_t* data, int size) {
-    USBDeviceConnected* dev = ep->getDevice();
-    HAL_HCD_HC_Init(&hhcd_USB_OTG_FS, CH_ISO_IN,
-        ep->getAddress(),
-        dev->getAddress(),
-        HCD_SPEED_FULL,
-        EP_TYPE_ISOC, ep->getSize());
-
-    token_done = false;
+    static bool init = false;
+    if (!init) {
+        init = true;
+        USBDeviceConnected* dev = ep->getDevice();
+        HAL_HCD_HC_Init(&hhcd_USB_OTG_FS, CH_ISO_IN,
+            ep->getAddress(), dev->getAddress(),
+            HCD_SPEED_FULL, EP_TYPE_ISOC, ep->getSize());
+    }
     HAL_HCD_HC_SubmitRequest(&hhcd_USB_OTG_FS, CH_ISO_IN, DIR_IN, EP_TYPE_ISOC, 1, data, size, 0);
-    while(!token_done);
-
-    switch(HAL_HCD_HC_GetURBState(&hhcd_USB_OTG_FS, CH_ISO_IN)) {
-        case URB_DONE:
+    while(HAL_HCD_HC_GetURBState(&hhcd_USB_OTG_FS, CH_ISO_IN) == URB_IDLE);
     return HAL_HCD_HC_GetXferCount(&hhcd_USB_OTG_FS, CH_ISO_IN);
-
-        default:
-            return -1;
-    }
 }
 
 #endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostC270/BaseUvc.cpp	Tue Jun 10 13:38:41 2014 +0900
@@ -0,0 +1,55 @@
+// 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) {
+        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;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostC270/BaseUvc.h	Tue Jun 10 13:38:41 2014 +0900
@@ -0,0 +1,51 @@
+// BaseUvc.h
+//#include "USBIsochronous.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;
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostC270/CamInfo.cpp	Tue Jun 10 13:38:41 2014 +0900
@@ -0,0 +1,188 @@
+// 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), \
+    }
+
+#define C210_PID 0x819
+#define C210_INFO(SIZE) {C270_VID, C210_PID, _##SIZE, 0, \
+    "C270", \
+    C270_MJPEG, \
+    C270_##SIZE, \
+    _5FPS, \
+    C270_EN, \
+    192, \
+    C270_IF_ALT(192), \
+    }
+
+// 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), \
+    }
+
+//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), \
+    }
+
+//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), \
+    }
+
+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);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostC270/USBHostCam.cpp	Tue Jun 10 13:38:41 2014 +0900
@@ -0,0 +1,191 @@
+// 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);
+                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;
+}
+
+#if 0
+void USBHostCam::setup() {
+    caminfo = CamInfoList;
+    bool found = false;
+    while(caminfo->vid != 0) {
+        if (caminfo->vid == host->getDevice(0)->getVid() &&
+            caminfo->pid == host->getDevice(0)->getPid() && 
+            caminfo->size == _caminfo_size && caminfo->option == _caminfo_option) {
+            found = true;
+            break;
+        }
+        caminfo++;
+    }
+    if (!found) {
+        CAM_INFO("caminfo not found.");
+        exit(1);
+    }
+    CAM_INFO("Found: %s", caminfo->name);
+
+    ep_iso_in.setAddress(caminfo->en);
+    ep_iso_in.setSize(caminfo->mps);
+    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");
+    }
+}
+#endif
+
+
+/*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);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostC270/USBHostCam.h	Tue Jun 10 13:38:41 2014 +0900
@@ -0,0 +1,98 @@
+// 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;
+};
+
+/** 
+ * 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();
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostC270/decodeMJPEG.cpp	Tue Jun 10 13:38:41 2014 +0900
@@ -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;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostC270/decodeMJPEG.h	Tue Jun 10 13:38:41 2014 +0900
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostGPS/USBHostGPS.cpp	Tue Jun 10 13:38:41 2014 +0900
@@ -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;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostGPS/USBHostGPS.h	Tue Jun 10 13:38:41 2014 +0900
@@ -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();
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostGPS/decodeNMEA.cpp	Tue Jun 10 13:38:41 2014 +0900
@@ -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;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostGPS/decodeNMEA.h	Tue Jun 10 13:38:41 2014 +0900
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostHID/USBHostKeyboard.cpp	Tue Jun 10 13:38:41 2014 +0900
@@ -0,0 +1,184 @@
+/* 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
+
+static uint8_t keymap[4][0x39] = { 
+    { 0, 0, 0, 0, 'a', 'b' /*0x05*/,
+      'c', 'd', 'e', 'f', 'g' /*0x0a*/,
+      'h', 'i', 'j', 'k', 'l'/*0x0f*/,
+      'm', 'n', 'o', 'p', 'q'/*0x14*/,
+      'r', 's', 't', 'u', 'v'/*0x19*/,
+      'w', 'x', 'y', 'z', '1'/*0x1E*/,
+      '2', '3', '4', '5', '6'/*0x23*/,
+      '7', '8', '9', '0', 0x0A /*enter*/, /*0x28*/
+      0x1B /*escape*/, 0x08 /*backspace*/, 0x09/*tab*/, 0x20/*space*/, '-', /*0x2d*/
+      '=', '[', ']', '\\', '#', /*0x32*/
+      ';', '\'', 0, ',', '.', /*0x37*/
+      '/'},
+
+    /* CTRL MODIFIER */
+    { 0, 0, 0, 0, 0, 0 /*0x05*/,
+      0, 0, 0, 0, 0 /*0x0a*/,
+      0, 0, 0, 0, 0/*0x0f*/,
+      0, 0, 0, 0, 0/*0x14*/,
+      0, 0, 0, 0, 0/*0x19*/,
+      0, 0, 0, 0, 0/*0x1E*/,
+      0, 0, 0, 0, 0/*0x23*/,
+      0, 0, 0, 0, 0 /*enter*/, /*0x28*/
+      0, 0, 0, 0, 0, /*0x2d*/
+      0, 0, 0, 0, 0, /*0x32*/
+      0, 0, 0, 0, 0, /*0x37*/
+      0},
+
+    /* SHIFT MODIFIER */
+    { 0, 0, 0, 0, 'A', 'B' /*0x05*/,
+      'C', 'D', 'E', 'F', 'G' /*0x0a*/,
+      'H', 'I', 'J', 'K', 'L'/*0x0f*/,
+      'M', 'N', 'O', 'P', 'Q'/*0x14*/,
+      'R', 'S', 'T', 'U', 'V'/*0x19*/,
+      'W', 'X', 'Y', 'Z', '!'/*0x1E*/,
+      '@', '#', '$', '%', '^'/*0x23*/,
+      '&', '*', '(', ')', 0, /*0x28*/
+      0, 0, 0, 0, 0, /*0x2d*/
+      '+', '{', '}', '|', '~', /*0x32*/
+      ':', '"', 0, '<', '>', /*0x37*/
+      '?'},
+
+    /* ALT MODIFIER */
+    { 0, 0, 0, 0, 0, 0 /*0x05*/,
+      0, 0, 0, 0, 0 /*0x0a*/,
+      0, 0, 0, 0, 0/*0x0f*/,
+      0, 0, 0, 0, 0/*0x14*/,
+      0, 0, 0, 0, 0/*0x19*/,
+      0, 0, 0, 0, 0/*0x1E*/,
+      0, 0, 0, 0, 0/*0x23*/,
+      0, 0, 0, 0, 0 /*enter*/, /*0x28*/
+      0, 0, 0, 0, 0, /*0x2d*/
+      0, 0, 0, 0, 0, /*0x32*/
+      0, 0, 0, 0, 0, /*0x37*/
+      0}
+
+};
+
+
+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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostHID/USBHostKeyboard.h	Tue Jun 10 13:38:41 2014 +0900
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostHID/USBHostMouse.cpp	Tue Jun 10 13:38:41 2014 +0900
@@ -0,0 +1,144 @@
+/* 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
+
+USBHostMouse::USBHostMouse() {
+    host = USBHost::getHostInst();
+    init();
+}
+
+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;
+}
+
+bool USBHostMouse::connected() {
+    return dev_connected;
+}
+
+bool USBHostMouse::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 (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);
+                host->interruptRead(dev, int_in, report, int_in->getSize(), false);
+                
+                dev_connected = true;
+                return true;
+            }
+        }
+    }
+    init();
+    return false;
+}
+
+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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostHID/USBHostMouse.h	Tue Jun 10 13:38:41 2014 +0900
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostRSSI/USBHostRSSI.cpp	Tue Jun 10 13:38:41 2014 +0900
@@ -0,0 +1,191 @@
+#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);
+                        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;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostRSSI/USBHostRSSI.h	Tue Jun 10 13:38:41 2014 +0900
@@ -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[];
+    } 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();
+};
+