BaseUsbHost example program

Dependencies:   BaseUsbHost FATFileSystem mbed mbed-rtos

Files at this revision

API Documentation at this revision

Comitter:
va009039
Date:
Tue Dec 04 13:39:57 2012 +0000
Child:
1:80205a2de336
Commit message:
first commit

Changed in this revision

BaseJpegDecode.lib Show annotated file Show diff for this revision Revisions of this file
BaseUsbHost.lib Show annotated file Show diff for this revision Revisions of this file
EthernetInterface.lib Show annotated file Show diff for this revision Revisions of this file
FATFileSystem.lib Show annotated file Show diff for this revision Revisions of this file
LogitechC270/LogitechC270.cpp Show annotated file Show diff for this revision Revisions of this file
LogitechC270/LogitechC270.h Show annotated file Show diff for this revision Revisions of this file
Terminal.lib Show annotated file Show diff for this revision Revisions of this file
UsbFlashDrive/UsbFlashDrive.cpp Show annotated file Show diff for this revision Revisions of this file
UsbFlashDrive/UsbFlashDrive.h Show annotated file Show diff for this revision Revisions of this file
UsbMouseHost/UsbMouseHost.cpp Show annotated file Show diff for this revision Revisions of this file
UsbMouseHost/UsbMouseHost.h Show annotated file Show diff for this revision Revisions of this file
example1_LogitechC270.cpp Show annotated file Show diff for this revision Revisions of this file
example1_UsbFlashDrive.cpp Show annotated file Show diff for this revision Revisions of this file
example1_UsbMouseHost.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-rtos.lib Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BaseJpegDecode.lib	Tue Dec 04 13:39:57 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/va009039/code/BaseJpegDecode/#a7547692071d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BaseUsbHost.lib	Tue Dec 04 13:39:57 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/va009039/code/BaseUsbHost/#b7d6879637a8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EthernetInterface.lib	Tue Dec 04 13:39:57 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/EthernetInterface/#a0ee3ae75cfa
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FATFileSystem.lib	Tue Dec 04 13:39:57 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/FATFileSystem/#b6669c987c8e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LogitechC270/LogitechC270.cpp	Tue Dec 04 13:39:57 2012 +0000
@@ -0,0 +1,157 @@
+// LogitechC270.cpp 2012/12/4
+#include "mbed.h"
+#include "rtos.h"
+#include "BaseUsbHost.h"
+#define DEBUG
+#include "BaseUsbHostDebug.h"
+#define TEST
+#include "BaseUsbHostTest.h"
+#include "LogitechC270.h"
+
+LogitechC270::LogitechC270(int frame, uint32_t interval, ControlEp* ctlEp)
+{
+    uint8_t buf[26];
+    
+    if (ctlEp == NULL) { // root hub
+        DBG_OHCI(LPC_USB->HcRhPortStatus1);
+        TEST_ASSERT_FALSE(LPC_USB->HcRhPortStatus1 & 0x200);
+        m_ctlEp = new ControlEp();
+        TEST_ASSERT_TRUE(m_ctlEp);
+    } else {
+        m_ctlEp = ctlEp;
+    }
+
+    int r = m_ctlEp->GetDescriptor(1, 0, buf, 18);
+    TEST_ASSERT(r == USB_OK);
+    DBG_HEX(buf, 18);
+    vid = *reinterpret_cast<uint16_t*>(buf+8);
+    pid = *reinterpret_cast<uint16_t*>(buf+10);
+    DBG("VID PID: %04X %04X\n", vid, pid);
+    TEST_ASSERT(vid == 0x046d && pid == 0x0825);
+    int addr = m_ctlEp->GetAddr();
+    DBG("addr: %d\n", addr);
+
+    m_isoEp = new IsochronousEp(addr, 0x81, 192);
+    TEST_ASSERT_TRUE(m_isoEp);
+
+    int rc = Control(GET_INFO, VS_PROBE_CONTROL, 1, buf, 1);
+    TEST_ASSERT(rc == USB_OK);
+    DBG_BYTES("GET_INFO Prob", buf, 1);
+
+    rc = Control(GET_DEF, VS_PROBE_CONTROL, 1, buf, 26);
+    TEST_ASSERT(rc == USB_OK);
+    DBG_BYTES("GET_DEF Probe", buf, 26);
+
+    rc = Control(GET_MIN, VS_PROBE_CONTROL, 1, buf, 26);
+    TEST_ASSERT(rc == USB_OK);
+    DBG_BYTES("GET_MIN Probe", buf, 26);
+
+    rc = Control(GET_MAX, VS_PROBE_CONTROL, 1, buf, 26);
+    TEST_ASSERT(rc == USB_OK);
+    DBG_BYTES("GET_MAX Probe", buf, 26);
+
+    rc = Control(GET_CUR, VS_PROBE_CONTROL, 1, buf, 26);
+    TEST_ASSERT(rc == USB_OK);
+    DBG_BYTES("GET_CUR Probe", buf, 26);
+
+    memset(buf, 0, 26);
+    buf[2] = C270_MJPEG;
+    buf[3] = frame;
+    *reinterpret_cast<uint32_t*>(buf+4) = interval;
+    
+    DBG_BYTES("SET_CUR Commit", buf, 26);
+    rc = Control(SET_CUR, VS_COMMIT_CONTROL, 1, buf, 26);
+    TEST_ASSERT(rc == USB_OK);
+
+    rc = Control(GET_CUR, VS_COMMIT_CONTROL, 1, buf, 26);
+    TEST_ASSERT(rc == USB_OK);
+    TEST_ASSERT_EQUAL(buf[2], C270_MJPEG);
+    TEST_ASSERT_EQUAL(buf[3], frame);
+    TEST_ASSERT_EQUAL(*reinterpret_cast<uint32_t*>(buf+4), interval);
+    DBG_BYTES("GET_CUR Commit", buf, 26);
+
+    int cfg;
+    rc = m_ctlEp->GetConfiguration(&cfg);
+    TEST_ASSERT_EQUAL(rc, USB_OK);
+    DBG("config: %d\n", cfg);
+
+    rc = m_ctlEp->SetConfiguration(1);
+    TEST_ASSERT_EQUAL(rc, USB_OK);
+
+    rc = m_ctlEp->GetConfiguration(&cfg);
+    TEST_ASSERT_EQUAL(rc, USB_OK);
+    DBG("config: %d\n", cfg);
+    TEST_ASSERT_EQUAL(cfg, 1);
+
+    int alt;
+    rc = m_ctlEp->GetInterface(1, &alt);
+    TEST_ASSERT_EQUAL(rc, USB_OK);
+    DBG("alt: %d\n", alt);
+
+    rc = m_ctlEp->SetInterfaceAlternate(1, 1); // alt=1 packet size = 192
+    TEST_ASSERT_EQUAL(rc, USB_OK);
+
+    rc = m_ctlEp->GetInterface(1, &alt);
+    TEST_ASSERT_EQUAL(rc, USB_OK);
+    DBG("alt: %d\n", alt);
+    TEST_ASSERT_EQUAL(alt, 1);
+
+    for(int i = 0; i < 16; i++) {
+        report_cc_count[i] = 0;
+        report_ps_cc_count[i] = 0;
+    }
+  
+    LPC_USB->HcControl |= OR_CONTROL_PLE; // PeriodicListEnable
+    LPC_USB->HcControl |= OR_CONTROL_IE;  // IsochronousEnable
+}
+
+void LogitechC270::poll()
+{
+    HCITD* itd = m_isoEp->read();
+    if (itd) {
+        uint8_t cc = itd->Control>>28;
+        report_cc_count[cc]++;
+        if (cc == 0) { // ConditionCode
+            //DBG_ITD(itd);
+            uint16_t frame = itd->Control & 0xffff;
+            uint8_t* buf = const_cast<uint8_t*>(itd->buf); 
+            int mps = m_isoEp->m_PacketSize;
+            for(int i = 0; i < m_isoEp->m_FrameCount; i++) {
+                uint16_t pswn = itd->OffsetPSW[i];
+                cc = pswn>>12;
+                if (cc == 0 || cc == 9) {
+                    int len = pswn & 0x7ff;
+                    onResult(frame, buf, len);
+               }
+               report_ps_cc_count[cc]++;
+               buf += mps;
+                frame++;
+            }
+        }
+        m_isoEp->delete_HCTD(reinterpret_cast<HCTD*>(itd));
+    }
+}
+
+int LogitechC270::Control(int req, int cs, int index, uint8_t* buf, int size)
+{
+    TEST_ASSERT(m_ctlEp);
+    int rc;
+    if (req == SET_CUR) {    
+        rc = m_ctlEp->controlSend(
+                    USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_INTERFACE, 
+                    req, cs<<8, index, buf, size);
+        return rc;
+    }
+    rc = m_ctlEp->controlReceive(
+                USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_INTERFACE, 
+                req, cs<<8, index, buf, size);
+    return rc;
+}
+
+void LogitechC270::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);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LogitechC270/LogitechC270.h	Tue Dec 04 13:39:57 2012 +0000
@@ -0,0 +1,77 @@
+#ifndef LOGITECH_C270_H
+#define LOGITECH_C270_H
+
+#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 _30FPS  333333
+#define _25FPS  400000
+#define _20FPS  500000
+#define _15FPS  666666
+#define _10FPS 1000000
+#define _5FPS  2000000
+
+#define C270_MJPEG 2
+#define C270_YUV2  1
+
+#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 LogitechC270 {
+public:
+    LogitechC270(int frame = C270_160x120, uint32_t interval = _5FPS, ControlEp* ctlEp = NULL);
+    void poll();
+    int Control(int req, int cs, int index, uint8_t* buf, int size);
+    uint16_t vid;
+    uint16_t pid;
+    ControlEp* m_ctlEp;
+    IsochronousEp* m_isoEp;
+    uint32_t report_cc_count[16];  // ConditionCode
+    uint32_t report_ps_cc_count[16]; // Packt Status ConditionCode
+    // callback
+    void onResult(uint16_t frame, uint8_t* buf, int len);
+    void setOnResult( void (*pMethod)(uint16_t, uint8_t*, int) )
+    {
+        m_pCb = pMethod;
+        m_pCbItem = NULL;
+        m_pCbMeth = NULL;
+    }
+    
+    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()
+    {
+        m_pCb = NULL;
+        m_pCbItem = NULL;
+        m_pCbMeth = NULL;
+    }
+    CDummy* m_pCbItem;
+    void (CDummy::*m_pCbMeth)(uint16_t, uint8_t*, int);
+    void (*m_pCb)(uint16_t, uint8_t*, int);
+};
+#endif //LOGITECH_C270_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Terminal.lib	Tue Dec 04 13:39:57 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/cbayley/code/Terminal/#543e8e498e09
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UsbFlashDrive/UsbFlashDrive.cpp	Tue Dec 04 13:39:57 2012 +0000
@@ -0,0 +1,388 @@
+// UsbFlashDrive.cpp 2012/12/4
+#include "mbed.h"
+#include "rtos.h"
+#include "BaseUsbHost.h"
+#define DEBUG
+#include "BaseUsbHostDebug.h"
+#define TEST
+#include "BaseUsbHostTest.h"
+
+#include "UsbFlashDrive.h"
+
+//#define WRITE_PROTECT
+
+int LE16(const uint8_t* d)
+{
+    return d[0] | (d[1] << 8);
+}
+
+uint32_t BE32(uint8_t* d)
+{
+    return (d[0] << 24) | (d[1] << 16) | (d[2] << 8) | d[3];
+}
+
+void BE16(uint32_t n, uint8_t* d)
+{
+    d[0] = (uint8_t)(n >> 8);
+    d[1] = (uint8_t)n;
+}
+
+void BE32(uint32_t n, uint8_t* d)
+{
+    d[0] = (uint8_t)(n >> 24);
+    d[1] = (uint8_t)(n >> 16);
+    d[2] = (uint8_t)(n >> 8);
+    d[3] = (uint8_t)n;
+}
+
+UsbFlashDrive::UsbFlashDrive(const char* name, ControlEp* ctlEp): FATFileSystem(name)
+{
+    m_name = name;
+    
+    if (ctlEp == NULL) { // root hub
+        DBG_OHCI(LPC_USB->HcRhPortStatus1);
+        TEST_ASSERT_FALSE(LPC_USB->HcRhPortStatus1 & 0x200);
+        m_ctlEp = new ControlEp();
+        TEST_ASSERT_TRUE(m_ctlEp);
+    } else {
+        m_ctlEp = ctlEp;
+    }
+
+    TEST_ASSERT(sizeof(CBW) == 31);
+    TEST_ASSERT(sizeof(CSW) == 13);
+
+    m_numBlocks = 0;
+    m_BlockSize = 0;
+    m_lun = 0;
+    m_interface = 0;
+    m_pEpBulkIn = NULL;
+    m_pEpBulkOut = NULL;
+    
+    ParseConfiguration();
+    int rc = m_ctlEp->SetConfiguration(1);
+    TEST_ASSERT_EQUAL(rc, USB_OK);
+    GetMaxLUN();
+    setup();
+}
+
+int UsbFlashDrive::disk_initialize()
+{
+    //DBG("m_BlockSize=%d\n", m_BlockSize);
+    if (m_BlockSize != 512) {
+        return 1;
+    }
+    return 0;    
+}
+
+int UsbFlashDrive::disk_write(const uint8_t* buffer, uint64_t sector)
+{
+    m_report_disk_write++;
+    //DBG("buffer=%p block_number=%d\n", buffer, sector);
+    int ret = MS_BulkSend(sector, 1, buffer);
+    if (ret >= 0) {
+        return 0;
+    }
+    return 1;
+}
+
+int UsbFlashDrive::disk_read(uint8_t* buffer, uint64_t sector)
+{
+    m_report_disk_read++;
+    //DBG("buffer=%p block_number=%d\n", buffer, sector);
+    int ret = MS_BulkRecv(sector, 1, buffer);
+    if (ret >= 0) {
+        return 0;
+    }
+    return 1;
+}    
+
+int UsbFlashDrive::disk_status()
+{
+    m_report_disk_status++;
+    return 0;
+}
+
+int UsbFlashDrive::disk_sync()
+{
+    m_report_disk_sync++;
+    return 0;
+}
+
+uint64_t UsbFlashDrive::disk_sectors()
+{
+    DBG("m_numBlocks=%d\n", m_numBlocks);
+    return m_numBlocks;
+}
+
+int UsbFlashDrive::setup(int timeout)
+{
+
+    int retry = 0;
+    Timer t;
+    t.start();
+    t.reset();
+    while(t.read_ms() < timeout) {
+        DBG("retry=%d t=%d\n", retry, t.read_ms());
+        if (retry > 80) {
+            return -1;
+        }
+        int rc = TestUnitReady();
+        DBG("TestUnitReady(): %d\n", rc);
+        if (rc == USB_OK) {
+            DBG("m_CSW.bCSWStatus: %02X\n", m_CSW.bCSWStatus);
+            if (m_CSW.bCSWStatus == 0x00) {
+                break;
+            }
+        }
+        GetSenseInfo();
+        retry++;
+        wait_ms(50);
+    }
+    if (t.read_ms() >= timeout) {
+        return -1;
+    }
+    ReadCapacity();
+    Inquire();
+    return 0;
+}
+
+int UsbFlashDrive::ParseConfiguration()
+{
+  int rc;
+  uint8_t ConfigDesc[9];
+  int index = 0;
+  TEST_ASSERT(m_ctlEp);
+  rc = m_ctlEp->GetDescriptor(USB_DESCRIPTOR_TYPE_CONFIGURATION, index, ConfigDesc, sizeof(ConfigDesc));
+  TEST_ASSERT(rc == USB_OK);
+  DBG_BYTES("ConfigDescriptor 9bytes", ConfigDesc, sizeof(ConfigDesc));
+  TEST_ASSERT(ConfigDesc[0] == 9);
+  TEST_ASSERT(ConfigDesc[1] == 0x02);
+  int wTotalLength = *((uint16_t*)&ConfigDesc[2]);
+  DBG("TotalLength: %d\n", wTotalLength);
+  int bConfigValue = ConfigDesc[5];
+  TEST_ASSERT(bConfigValue == 1);
+  DBG("ConfigValue: %d\n", bConfigValue);
+  DBG("MaxPower: %d mA\n", ConfigDesc[8]*2);   
+
+  uint8_t* buf = new uint8_t[wTotalLength];
+  TEST_ASSERT(buf);
+  rc = m_ctlEp->GetDescriptor(USB_DESCRIPTOR_TYPE_CONFIGURATION, index, buf, wTotalLength);
+  TEST_ASSERT(rc == USB_OK);
+  TEST_ASSERT(ConfigDesc[1] == 0x02);
+  for (int pos = 0; pos < wTotalLength; pos += buf[pos]) {
+      DBG_BYTES("CFG", buf+pos, buf[pos]);
+      int type = buf[pos+1];
+      if (USB_DESCRIPTOR_TYPE_INTERFACE == type) { // 0x04
+        DBG("InterfaceNumber: %d\n", buf[pos+2]);
+        DBG("AlternateSetting: %d\n", buf[pos+3]);
+        DBG("NumEndpoint: %d\n", buf[pos+4]);
+        DBG("InterfaceClass: %02X\n", buf[pos+5]);
+        DBG("InterfaceSubClass: %02X\n", buf[pos+6]);
+        DBG("InterfaceProtocol: %02X\n", buf[pos+7]);
+        TEST_ASSERT(buf[pos+6] == 0x06); // SCSI
+        TEST_ASSERT(buf[pos+7] == 0x50); // bulk only
+      } 
+      if (USB_DESCRIPTOR_TYPE_ENDPOINT == type) {
+          TEST_ASSERT(buf[pos] == 7);
+          uint8_t att = buf[pos+3];
+          if (att == 2) { // bulk
+              uint8_t ep = buf[pos+2];
+              bool dir = ep & 0x80; // true=IN
+              uint16_t size = LE16(buf+pos+4);
+              DBG("EndpointAddress: %02X\n", ep);
+              DBG("Attribute: %02X\n", att);
+              DBG("MaxPacketSize: %d\n", size); 
+              BulkEp* pEp = new BulkEp(m_ctlEp->GetAddr(), ep, size);
+              TEST_ASSERT(pEp);
+              if (dir) {
+                  m_pEpBulkIn = pEp;
+              } else {
+                  m_pEpBulkOut = pEp;
+              } 
+          }
+      }
+  }
+  delete[] buf;
+  TEST_ASSERT(m_pEpBulkIn);
+  TEST_ASSERT(m_pEpBulkOut);
+  return 0;   
+}
+
+int UsbFlashDrive::BulkOnlyMassStorageReset()
+{
+    TEST_ASSERT(m_ctlEp);
+    int rc = m_ctlEp->controlReceive(0x21, 0xff, 0x0000, m_interface, NULL, 0); 
+    TEST_ASSERT(rc == USB_OK);
+    return rc;
+}
+
+int UsbFlashDrive::GetMaxLUN()
+{
+    TEST_ASSERT(m_interface == 0);
+    uint8_t temp[1];
+    TEST_ASSERT(m_ctlEp);
+    int rc = m_ctlEp->controlReceive(0xa1, 0xfe, 0x0000, m_interface, temp, sizeof(temp)); 
+    TEST_ASSERT(rc == USB_OK);
+    DBG_BYTES("GetMaxLUN", temp, sizeof(temp));
+    m_MaxLUN = temp[0];
+    TEST_ASSERT(m_MaxLUN <= 15);
+    return rc;
+}
+
+
+int UsbFlashDrive::TestUnitReady()
+{
+    const uint8_t cdb[6] = {SCSI_CMD_TEST_UNIT_READY, 0x00, 0x00, 0x00, 0x00, 0x00};
+    m_CBW.dCBWDataTraansferLength = 0;
+    m_CBW.bmCBWFlags = 0x00;
+    CommandTransport(cdb, sizeof(cdb));
+    StatusTransport();
+    return 0;
+}
+
+int UsbFlashDrive::GetSenseInfo()
+{
+    const uint8_t cdb[6] = {SCSI_CMD_REQUEST_SENSE, 0x00, 0x00, 0x00, 18, 0x00};
+    m_CBW.dCBWDataTraansferLength = 18;
+    m_CBW.bmCBWFlags = 0x80; // data In
+    CommandTransport(cdb, sizeof(cdb));
+
+    uint8_t buf[18];
+    _bulkRecv(buf, sizeof(buf));
+    DBG_HEX(buf, sizeof(buf));
+
+    StatusTransport();
+    TEST_ASSERT(m_CSW.bCSWStatus == 0x00);
+    return 0;
+}
+
+int UsbFlashDrive::ReadCapacity()
+{
+    const uint8_t cdb[10] = {SCSI_CMD_READ_CAPACITY, 0x00, 0x00, 0x00, 0x00, 
+                                               0x00, 0x00, 0x00, 0x00, 0x00};
+    m_CBW.dCBWDataTraansferLength = 8;
+    m_CBW.bmCBWFlags = 0x80; // data In
+    CommandTransport(cdb, sizeof(cdb));
+
+    uint8_t buf[8];
+    int rc = _bulkRecv(buf, sizeof(buf));
+    TEST_ASSERT(rc >= 0);
+    DBG_HEX(buf, sizeof(buf));
+
+    StatusTransport();
+    TEST_ASSERT(m_CSW.bCSWStatus == 0x00);
+    
+    m_numBlocks = BE32(buf);
+    m_BlockSize = BE32(buf+4);
+    DBG("m_numBlocks=%d m_BlockSize=%d\n", m_numBlocks, m_BlockSize);
+    TEST_ASSERT(m_BlockSize == 512);
+    TEST_ASSERT(m_numBlocks > 0);
+    return 0;
+}
+
+int UsbFlashDrive::Inquire()
+{
+    const uint8_t cdb[6] = {SCSI_CMD_INQUIRY, 0x00, 0x00, 0x00, 36, 0x00};
+    m_CBW.dCBWDataTraansferLength = 36;
+    m_CBW.bmCBWFlags = 0x80; // data In
+    CommandTransport(cdb, sizeof(cdb));
+
+    uint8_t buf[36];
+    int rc = _bulkRecv(buf, sizeof(buf));
+    TEST_ASSERT(rc >= 0);
+    DBG_HEX(buf, sizeof(buf));
+
+    StatusTransport();
+    return 0;
+}
+
+int UsbFlashDrive::MS_BulkRecv(uint32_t block_number, int num_blocks, uint8_t* user_buffer)
+{
+    TEST_ASSERT(m_BlockSize == 512);
+    TEST_ASSERT(num_blocks == 1);
+    TEST_ASSERT(user_buffer);
+    uint8_t cdb[10] = {SCSI_CMD_READ_10, 0x00, 0x00, 0x00, 0x00, 
+                                   0x00, 0x00, 0x00, 0x00, 0x00};
+    BE32(block_number, cdb+2);
+    BE16(num_blocks, cdb+7);
+    uint32_t len = m_BlockSize * num_blocks;
+    TEST_ASSERT(len <= 512);
+    m_CBW.dCBWDataTraansferLength = len;
+    m_CBW.bmCBWFlags = 0x80; // data In
+    CommandTransport(cdb, sizeof(cdb));
+
+    int ret = _bulkRecv(user_buffer, len);
+    //DBG_HEX(user_buffer, len);
+
+    StatusTransport();
+    TEST_ASSERT(m_CSW.bCSWStatus == 0x00);
+    return ret;
+}
+
+int UsbFlashDrive::MS_BulkSend(uint32_t block_number, int num_blocks, const uint8_t* user_buffer)
+{
+#ifdef WRITE_PROTECT
+    return 0;
+#else
+    TEST_ASSERT(num_blocks == 1);
+    TEST_ASSERT(user_buffer);
+    uint8_t cdb[10] = {SCSI_CMD_WRITE_10, 0x00, 0x00, 0x00, 0x00, 
+                                    0x00, 0x00, 0x00, 0x00, 0x00};
+    BE32(block_number, cdb+2);
+    BE16(num_blocks, cdb+7);
+    uint32_t len = m_BlockSize * num_blocks;
+    TEST_ASSERT(len <= 512);
+    m_CBW.dCBWDataTraansferLength = len;
+    m_CBW.bmCBWFlags = 0x00; // data Out
+    CommandTransport(cdb, sizeof(cdb));
+
+    int ret = _bulkSend(user_buffer, len);
+    //DBG_HEX(user_buffer, len);
+
+    StatusTransport();
+    TEST_ASSERT(m_CSW.bCSWStatus == 0x00);
+    return ret;
+#endif //WRITE_PROTECT    
+}
+
+int UsbFlashDrive::CommandTransport(const uint8_t* cdb, int size)
+{
+    TEST_ASSERT(cdb);
+    TEST_ASSERT(size >= 6);
+    TEST_ASSERT(size <= 16);
+    m_CBW.bCBWLUN = m_lun;
+    m_CBW.bCBWCBLength = size;
+    memcpy(m_CBW.CBWCB, cdb, size);
+
+    m_CBW.dCBWSignature = 0x43425355;
+    m_CBW.dCBWTag = m_tag++;
+    m_CBW.bCBWLUN = 0;
+    //DBG_HEX((uint8_t*)&m_CBW, sizeof(CBW));
+    int rc = _bulkSend((uint8_t*)&m_CBW, sizeof(CBW));
+    return rc;
+}
+
+int UsbFlashDrive::StatusTransport()
+{
+    TEST_ASSERT(sizeof(CSW) == 13);
+    int rc = _bulkRecv((uint8_t*)&m_CSW, sizeof(CSW));
+    //DBG_HEX((uint8_t*)&m_CSW, sizeof(CSW));
+    TEST_ASSERT(m_CSW.dCSWSignature == 0x53425355);
+    TEST_ASSERT(m_CSW.dCSWTag == m_CBW.dCBWTag);
+    TEST_ASSERT(m_CSW.dCSWDataResidue == 0);
+    return rc;
+}
+
+int UsbFlashDrive::_bulkRecv(uint8_t* buf, int size)
+{
+    TEST_ASSERT(m_pEpBulkIn);
+    int ret = m_pEpBulkIn->read(buf, size);
+    return ret;
+}
+
+int UsbFlashDrive::_bulkSend(const uint8_t* buf, int size)
+{
+    TEST_ASSERT(m_pEpBulkOut);
+    int ret = m_pEpBulkOut->write(buf, size);
+    return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UsbFlashDrive/UsbFlashDrive.h	Tue Dec 04 13:39:57 2012 +0000
@@ -0,0 +1,78 @@
+// usbFlashDrive.h 2012/12/4
+#ifndef USB_FLASH_DRIVE_H
+#define USB_FLASH_DRIVE_H
+
+#include "FATFileSystem.h"
+
+#define  SCSI_CMD_REQUEST_SENSE      0x03
+#define  SCSI_CMD_TEST_UNIT_READY    0x00
+#define  SCSI_CMD_INQUIRY            0x12
+#define  SCSI_CMD_READ_10            0x28
+#define  SCSI_CMD_READ_CAPACITY      0x25
+#define  SCSI_CMD_WRITE_10           0x2A
+
+#pragma pack(push,1)
+typedef struct {
+    uint32_t dCBWSignature;
+    uint32_t dCBWTag;
+    uint32_t dCBWDataTraansferLength;
+    uint8_t bmCBWFlags;
+    uint8_t bCBWLUN;
+    uint8_t bCBWCBLength;
+    uint8_t CBWCB[16];
+} CBW;
+
+typedef struct {
+    uint32_t dCSWSignature;
+    uint32_t dCSWTag;
+    uint32_t dCSWDataResidue;
+    uint8_t  bCSWStatus;
+} CSW;
+#pragma pack(pop)
+
+class UsbFlashDrive : public FATFileSystem {
+public:
+    UsbFlashDrive(const char* name, ControlEp* ctlEp = NULL);
+    virtual int disk_initialize();
+    virtual int disk_write(const uint8_t* buffer, uint64_t sector);
+    virtual int disk_read(uint8_t* buffer, uint64_t sector);    
+    virtual int disk_status();
+    virtual int disk_sync();
+    virtual uint64_t disk_sectors();
+
+    int setup(int timeout = 9000);
+private:
+    int ParseConfiguration();
+    int BulkOnlyMassStorageReset();
+    int GetMaxLUN();
+    int ReadCapacity();
+    int GetSenseInfo();
+    int TestUnitReady();
+    int Inquire();
+    int MS_BulkRecv(uint32_t block_number, int num_blocks, uint8_t* user_buffer);
+    int MS_BulkSend(uint32_t block_number, int num_blocks, const uint8_t* user_buffer);
+    int CommandTransport(const uint8_t* cdb, int size);
+    int StatusTransport();
+    int _bulkRecv(uint8_t* buf, int size);
+    int _bulkSend(const uint8_t* buf, int size);
+    const char* m_name;
+    int m_drive;
+    uint32_t m_numBlocks;
+    int m_BlockSize;
+    int m_lun;
+    int m_MaxLUN;
+    int m_interface;
+    uint32_t m_tag;
+    CBW m_CBW;
+    CSW m_CSW;
+    ControlEp* m_ctlEp;
+    BulkEp* m_pEpBulkIn;
+    BulkEp* m_pEpBulkOut;
+    // report
+    uint32_t m_report_disk_write;
+    uint32_t m_report_disk_read;
+    uint32_t m_report_disk_status;
+    uint32_t m_report_disk_sync;
+};
+
+#endif // USB_FLASH_DRIVE_H
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UsbMouseHost/UsbMouseHost.cpp	Tue Dec 04 13:39:57 2012 +0000
@@ -0,0 +1,42 @@
+// UsbMouseHost.cpp
+#include "mbed.h"
+#include "rtos.h"
+#include "BaseUsbHost.h"
+//#define DEBUG
+#include "BaseUsbHostDebug.h"
+#define TEST
+#include "BaseUsbHostTest.h"
+#include "UsbMouseHost.h"
+
+UsbMouseHost::UsbMouseHost(ControlEp* ctlEp)
+{
+    if (ctlEp == NULL) { // root hub
+        DBG_OHCI(LPC_USB->HcRhPortStatus1);
+        int lowSpeed = 0;
+        if (LPC_USB->HcRhPortStatus1 & 0x200) {
+            lowSpeed = 1;
+        }
+        m_ctlEp = new ControlEp(lowSpeed);
+        TEST_ASSERT_TRUE(m_ctlEp);
+    } else {
+        m_ctlEp = ctlEp;
+    }
+
+    int rc = m_ctlEp->SetConfiguration(1);
+    TEST_ASSERT_EQUAL(rc, USB_OK);
+
+    int addr = m_ctlEp->GetAddr();
+    int lowSpeed = m_ctlEp->GetLowSpeed();
+    m_intEp = new InterruptEp(addr, 0x81, 8, lowSpeed);
+    TEST_ASSERT_TRUE(m_intEp);
+}
+
+int UsbMouseHost::read(uint32_t* status, int millisec)
+{
+    int rc = m_intEp->read(reinterpret_cast<uint8_t*>(status), 4, millisec);
+    if (rc < 0) { // error?
+        *status = 0x00000000;
+        return rc;
+    }
+    return USB_OK;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UsbMouseHost/UsbMouseHost.h	Tue Dec 04 13:39:57 2012 +0000
@@ -0,0 +1,13 @@
+// UsbMouseHost.h
+#ifndef USB_MOUSE_HOST_H
+#define USB_MOUSE_HOST_H
+
+class UsbMouseHost {
+public:
+    UsbMouseHost(ControlEp* ctlEp = NULL);
+    int read(uint32_t* status, int millisec=osWaitForever);
+    ControlEp* m_ctlEp;
+    InterruptEp* m_intEp;
+};
+
+#endif //USB_MOUSE_HOST_H
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/example1_LogitechC270.cpp	Tue Dec 04 13:39:57 2012 +0000
@@ -0,0 +1,153 @@
+#if 1
+//
+// simple color tracking
+//
+#include "mbed.h"
+#include "rtos.h"
+#include "BaseUsbHost.h"
+#define DEBUG
+#include "BaseUsbHostDebug.h"
+#define TEST
+#include "BaseUsbHostTest.h"
+#include "LogitechC270.h"
+#include "BaseJpegDecode.h"
+#include "Terminal.h"
+
+// Logitech C270
+#define WIDTH  160
+#define HEIGHT 120
+
+#define THRESHOLD 200
+
+DigitalOut led1(LED1), led2(LED2), led3(LED3), led4(LED4);
+Terminal term(USBTX, USBRX);
+
+class CalcCenter : public BaseJpegDecode {
+public:
+    int y_center, x_center;
+    int m_x_sum, m_y_sum, m_sum;
+    uint32_t EOI_count;
+    int16_t m_buf[WIDTH/16*HEIGHT/8];
+    CalcCenter():EOI_count(0) {
+        memset(m_buf, 0, sizeof(m_buf));
+    }
+    virtual void outputDC(int mcu, int block, int value) {
+        if (mcu >= (WIDTH/16*HEIGHT/8)) {
+            return;
+        }
+        if (block == 3) { // 0-1:Y 2:Cb 3:Cr
+            value *= qt[1][0];
+            m_buf[mcu] = value; // debug
+            if (value >= THRESHOLD) { // red
+                m_x_sum += value*(mcu%(WIDTH/16));
+                m_y_sum += value*(mcu/(WIDTH/16));
+                m_sum += value;
+            }
+        }
+    }
+    virtual void outputAC(int mcu, int block, int scan, int value){};
+    virtual void outputMARK(uint8_t c){
+        if (c == 0xd9) { // EOI
+            if(m_sum == 0) {
+                x_center = y_center = -1; // not found
+            } else {
+                x_center = m_x_sum / m_sum;
+                y_center = m_y_sum / m_sum;
+            }
+            m_x_sum = m_y_sum = m_sum = 0; // reset
+            EOI_count++;
+            led3 = !led3;
+        }
+    };
+};
+
+CalcCenter* calc = NULL;
+void callback_motion_jpeg(uint16_t frame, uint8_t* buf, int len)
+{
+    if (calc) {
+        calc->input(buf+12, len-12);
+    }
+    if (buf[1]&1) { // FID
+        led1 = !led1;
+    }
+}
+
+BaseUsbHost *UsbHost;
+UsbHub* hub;
+ControlEp* ctlEp = NULL;
+LogitechC270* cam;
+
+void display_thread(void const *args) {
+    Timer t;
+    term.cls();
+    int fg, old_fg = 0xffffff;
+    while(1) {
+        int y;
+        for(y = 0; y < HEIGHT/8; y++) {
+            term.locate(0, y);
+            for(int x = 0; x < WIDTH/16; x++) {
+                int value = calc->m_buf[y*WIDTH/16+x];
+                if (value >= THRESHOLD) {
+                    fg = 0xff0000; // red
+                } else {
+                    fg = 0xffffff; // white
+                }
+                if (fg != old_fg) {
+                    term.foreground(fg);
+                    old_fg = fg;
+                }
+                term.printf("%+4d,", value);
+            }
+        }
+        term.locate(0, y);
+        term.printf("Cr:(%d,%d)[width=%d height=%d yblock=%d %u %u]\n", 
+            calc->x_center, calc->y_center, calc->width, calc->height, calc->yblock, calc->EOI_count, t.read_ms()/1000);
+        term.printf("[CC:"); 
+        for(int i = 0; i < 16; i++) {
+            term.printf(" %u", cam->report_cc_count[i]); 
+        }
+        term.printf("]\n"); 
+        term.printf("[PS:"); 
+        for(int i = 0; i < 16; i++) {
+            term.printf(" %u", cam->report_ps_cc_count[i]); 
+        }
+        term.printf("]\n"); 
+        Thread::wait(200);
+        //Thread::signal_wait(1, 2000);
+        led2 = !led2;
+    }
+}
+
+int main() {
+    term.baud(921600);
+    term.printf("%s\n", __FILE__);
+
+    calc = new CalcCenter;
+    TEST_ASSERT(calc);
+
+    UsbHost = new BaseUsbHost;
+    TEST_ASSERT_TRUE(UsbHost);
+
+    UsbHub* hub = new UsbHub();
+    TEST_ASSERT_TRUE(hub);
+
+    for(int i = 0; i < 4; i++) {
+        if (hub->PortEp[i]) {
+            if (hub->PortEp[i]->DeviceClass == 0x02) {  
+                ctlEp = hub->PortEp[i];
+                break;
+            }
+        }
+    }
+    
+    cam = new LogitechC270(C270_160x120, _15FPS, ctlEp); 
+    TEST_ASSERT_TRUE(cam);
+    cam->setOnResult(callback_motion_jpeg);
+
+    Thread thread(display_thread, NULL, osPriorityBelowNormal);
+ 
+    while(1) {
+        cam->poll();
+    }
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/example1_UsbFlashDrive.cpp	Tue Dec 04 13:39:57 2012 +0000
@@ -0,0 +1,90 @@
+#if 0
+#include "mbed.h"
+#include "rtos.h"
+#include "BaseUsbHost.h"
+#define DEBUG
+#include "BaseUsbHostDebug.h"
+#define TEST
+#include "BaseUsbHostTest.h"
+#include "UsbFlashDrive.h"
+
+DigitalOut led1(LED1), led2(LED2), led3(LED3), led4(LED4);
+Serial pc(USBTX, USBRX);
+
+BaseUsbHost *UsbHost;
+UsbHub* hub;
+ControlEp* ctlEp = NULL;
+UsbFlashDrive* drive;
+int main() {
+    pc.baud(921600);
+    printf("%s\n", __FILE__);
+
+    UsbHost = new BaseUsbHost;
+    TEST_ASSERT_TRUE(UsbHost);
+
+    UsbHub* hub = new UsbHub();
+    TEST_ASSERT_TRUE(hub);
+
+    for(int i = 0; i < MAX_HUB_PORT; i++) {
+        if (hub->PortEp[i]) {
+            if (hub->PortEp[i]->DeviceClass == 0x01) {  
+                ctlEp = hub->PortEp[i];
+                break;
+            }
+        }
+    }
+
+    drive = new UsbFlashDrive("usb", ctlEp);
+    TEST_ASSERT(drive);
+
+
+    const int file_size = 1024*256;
+    printf("USB FLASH DRIVE read/write file size: %d bytes\n", file_size);
+    
+    char path[32];
+    int size;
+    Timer t;
+    for(int n = 0; n <= 9; n++) {
+        sprintf(path, "/usb/test%d.txt", n);
+        FILE* fp = fopen(path, "wb");
+        size = 0;
+        t.reset();
+        t.start();
+        if (fp) {
+            for(int i = 0; i < file_size; i++) {
+                int c = i & 0xff;
+                fputc(c, fp);
+                size++;
+            }
+            t.stop();
+            fclose(fp);
+        }
+        printf("write file %d bytes %d ms %s\n", size, t.read_ms(), path);
+        led1 = !led1;
+    }
+    
+    for(int n = 0; n <=9; n++) {
+        sprintf(path, "/usb/test%d.txt", n);
+        FILE* fp = fopen(path, "rb");
+        size = 0;
+        t.reset();
+        t.start();
+        if (fp) {
+            while(1) {
+                int c = fgetc(fp);
+                if (c == EOF) {
+                    break;
+                }
+                size++;
+            } 
+            t.stop();
+            fclose(fp);
+        }
+        printf("read file %d bytes %d ms %s\n", size, t.read_ms(), path);
+        led2 = !led2;
+    }
+
+    exit(1);
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/example1_UsbMouseHost.cpp	Tue Dec 04 13:39:57 2012 +0000
@@ -0,0 +1,54 @@
+#if 0
+#include "mbed.h"
+#include "rtos.h"
+#include "BaseUsbHost.h"
+#define DEBUG
+#include "BaseUsbHostDebug.h"
+#define TEST
+#include "BaseUsbHostTest.h"
+#include "UsbMouseHost.h"
+
+Serial pc(USBTX, USBRX);
+DigitalOut led1(LED1);
+
+BaseUsbHost *UsbHost;
+UsbHub* hub;
+ControlEp* ctlEp = NULL;
+UsbMouseHost* mouse;
+int main() {
+    pc.baud(921600);
+    printf("%s\n", __FILE__);
+
+    UsbHost = new BaseUsbHost;
+    TEST_ASSERT_TRUE(UsbHost);
+
+    UsbHub* hub = new UsbHub();
+    TEST_ASSERT_TRUE(hub);
+
+    for(int i = 0; i < 4; i++) {
+        ctlEp = hub->PortEp[i];
+        if (ctlEp) {
+            break;
+        }
+    }
+
+    mouse = new UsbMouseHost(ctlEp);
+    TEST_ASSERT(mouse);
+
+ 
+    while(1) {
+        uint32_t status;
+        int r = mouse->read(&status);
+        if (r == USB_OK) {
+            printf("%08X\n", status);
+            if (status & 1) { // left 
+                led1 = !led1;
+            } else if (status & 2) { // right 
+                break;
+            }
+        }
+    }
+    exit(1);
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-rtos.lib	Tue Dec 04 13:39:57 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed-rtos/#88a1a9c26ae3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Tue Dec 04 13:39:57 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/b60934f96c0c
\ No newline at end of file