Simple USBHost library for Nucleo F446RE/F411RE/F401RE FRDM-KL46Z/KL25Z/F64F LPC4088/LPC1768
Dependents: F401RE-BTstack_example F401RE-USBHostMSD_HelloWorld
Fork of KL46Z-USBHost by
簡易USBホストライブラリです。
official-USBHostの下位互換で対応プログラムを僅かな修正で動かすことが出来ます。
Platforms
- Nucleo F446RE
- Nucleo F411RE
- Nucleo F401RE
- FRDM-K64F
- FRDM-KL46Z
- FRDM-KL25Z
- LPC4088
- LPC1768
Nucleo F446RE/F411RE/F401REのUSB接続方法
ST morpho | USB |
---|---|
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
Revision 8:6463cd1964c0, committed 2014-01-31
- Comitter:
- va009039
- Date:
- Fri Jan 31 13:45:07 2014 +0000
- Parent:
- 7:9a20482c9a7a
- Child:
- 9:7f9f64cf5ded
- Commit message:
- USB hub support.
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/IUSBEnumerator.h Fri Jan 31 13:45:07 2014 +0000 @@ -0,0 +1,36 @@ +/* mbed USBHost Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef IUSBENUMERATOR_H_ +#define IUSBENUMERATOR_H_ + +#include "stdint.h" +#include "USBEndpoint.h" + +/* +Generic interface to implement for "smart" USB enumeration +*/ + +class IUSBEnumerator +{ +public: + virtual void setVidPid(uint16_t vid, uint16_t pid) = 0; + virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) = 0; //Must return true if the interface should be parsed + virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) = 0; //Must return true if the endpoint will be used +}; + +#endif /*IUSBENUMERATOR_H_*/ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/USBDeviceConnected.cpp Fri Jan 31 13:45:07 2014 +0000 @@ -0,0 +1,125 @@ +/* mbed USBHost Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "USBDeviceConnected.h" +//#include "dbg.h" +#define USB_DBG(...) while(0) + +USBDeviceConnected::USBDeviceConnected() { + init(); +} + +void USBDeviceConnected::init() { + hub_nb = 0; + port = 0; + vid = 0; + pid = 0; + nb_interf = 0; + enumerated = false; + //activeAddr = false; + //sizeControlEndpoint = 8; + device_class = 0; + device_subclass = 0; + proto = 0; + lowSpeed = false; + for (int i = 0; i < MAX_INTF; i++) { + memset((void *)&intf[i], 0, sizeof(INTERFACE)); + intf[i].in_use = false; + for (int j = 0; j < MAX_ENDPOINT_PER_INTERFACE; j++) { + intf[i].ep[j] = NULL; + //strcpy(intf[i].name, "Unknown"); + } + } + //hub_parent = NULL; + //hub = NULL; + nb_interf = 0; +} + +INTERFACE * USBDeviceConnected::getInterface(uint8_t index) { + if (index >= MAX_INTF) + return NULL; + + if (intf[index].in_use) + return &intf[index]; + + return NULL; +} + +bool USBDeviceConnected::addInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) { + if ((intf_nb >= MAX_INTF) || (intf[intf_nb].in_use)) { + return false; + } + intf[intf_nb].in_use = true; + intf[intf_nb].intf_class = intf_class; + intf[intf_nb].intf_subclass = intf_subclass; + intf[intf_nb].intf_protocol = intf_protocol; + intf[intf_nb].nb_endpoint = 0; + return true; +} + +bool USBDeviceConnected::addEndpoint(uint8_t intf_nb, USBEndpoint * ept) { + if ((intf_nb >= MAX_INTF) || (intf[intf_nb].in_use == false) || (intf[intf_nb].nb_endpoint >= MAX_ENDPOINT_PER_INTERFACE)) { + return false; + } + intf[intf_nb].nb_endpoint++; + + for (int i = 0; i < MAX_ENDPOINT_PER_INTERFACE; i++) { + if (intf[intf_nb].ep[i] == NULL) { + intf[intf_nb].ep[i] = ept; + return true; + } + } + return false; +} + +void USBDeviceConnected::init(uint8_t hub_, uint8_t port_, bool lowSpeed_) { + USB_DBG("init dev: %p", this); + init(); + hub_nb = hub_; + port = port_; + lowSpeed = lowSpeed_; +} + +void USBDeviceConnected::disconnect() { + //for(int i = 0; i < MAX_INTF; i++) { + // intf[i].detach.call(); + //} + //init(); +} + + +USBEndpoint * USBDeviceConnected::getEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir, uint8_t index) { + if (intf_nb >= MAX_INTF) { + return NULL; + } + for (int i = 0; i < MAX_ENDPOINT_PER_INTERFACE; i++) { + if ((intf[intf_nb].ep[i]->getType() == type) && (intf[intf_nb].ep[i]->getDir() == dir)) { + if(index) { + index--; + } else { + return intf[intf_nb].ep[i]; + } + } + } + return NULL; +} + +USBEndpoint * USBDeviceConnected::getEndpoint(uint8_t intf_nb, uint8_t index) { + if ((intf_nb >= MAX_INTF) || (index >= MAX_ENDPOINT_PER_INTERFACE)) { + return NULL; + } + return intf[intf_nb].ep[index]; +}
--- a/USBHost/USBDeviceConnected.h Tue Jan 28 06:50:12 2014 +0000 +++ b/USBHost/USBDeviceConnected.h Fri Jan 31 13:45:07 2014 +0000 @@ -18,13 +18,122 @@ #include "USBEndpoint.h" #include "USBHostConf.h" +class USBEndpoint; + +typedef struct { + bool in_use; + uint8_t nb_endpoint; + uint8_t intf_class; + uint8_t intf_subclass; + uint8_t intf_protocol; + USBEndpoint * ep[MAX_ENDPOINT_PER_INTERFACE]; + //FunctionPointer detach; + //char name[10]; +} INTERFACE; + /** * USBDeviceConnected class */ -class USBDeviceConnected -{ +class USBDeviceConnected { public: + + /** + * Constructor + */ + USBDeviceConnected(); + + /** + * Attach an USBEndpoint to this device + * + * @param intf_nb interface number + * @param ep pointeur on the USBEndpoint which will be attached + * @returns true if successful, false otherwise + */ + bool addEndpoint(uint8_t intf_nb, USBEndpoint * ep); + + /** + * Retrieve an USBEndpoint by its TYPE and DIRECTION + * + * @param intf_nb the interface on which to lookup the USBEndpoint + * @param type type of the USBEndpoint looked for + * @param dir direction of the USBEndpoint looked for + * @param index the index of the USBEndpoint whitin the interface + * @returns pointer on the USBEndpoint if found, NULL otherwise + */ + USBEndpoint * getEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir, uint8_t index = 0); + + /** + * Retrieve an USBEndpoint by its index + * + * @param intf_nb interface number + * @param index index of the USBEndpoint + * @returns pointer on the USBEndpoint if found, NULL otherwise + */ + USBEndpoint * getEndpoint(uint8_t intf_nb, uint8_t index); + + /** + * Add a new interface to this device + * + * @param intf_nb interface number + * @param intf_class interface class + * @param intf_subclass interface subclass + * @param intf_protocol interface protocol + * @returns true if successful, false otherwise + */ + bool addInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); + + /** + * Get a specific interface + * + * @param index index of the interface to be fetched + * @returns interface + */ + INTERFACE * getInterface(uint8_t index); + + /** + * Disconnect the device by calling a callback function registered by a driver + */ + void disconnect(); + + void init(uint8_t hub, uint8_t _port, bool _lowSpeed); + void setAddress(uint8_t addr_) { addr = addr_; }; + void setVid(uint16_t vid_) { vid = vid_; }; + void setPid(uint16_t pid_) { pid = pid_; }; + void setClass(uint8_t device_class_) { device_class = device_class_; } + void setSubClass(uint8_t device_subclass_) { device_subclass = device_subclass_; }; + void setProtocol(uint8_t pr) { proto = pr; }; + void setEnumerated() { enumerated = true; }; + void setNbIntf(uint8_t nb_intf) {nb_interf = nb_intf; }; + void setSpeed(bool _lowSpeed) { lowSpeed = _lowSpeed; } + void setName(const char * name_, uint8_t intf_nb) { return; }; + void setEpCtl(USBEndpoint* ep) { ep_ctl = ep; } + + static int getNewAddress() { + static int addr = 1; + return addr++; + } + uint8_t getHub() { return hub_nb; }; + uint8_t getAddress() { return addr; }; + uint16_t getVid() { return vid; }; + uint16_t getPid() { return pid; }; + uint8_t getClass() { return device_class; }; + bool getSpeed() { return lowSpeed; } + bool isEnumerated() { return enumerated; }; + USBEndpoint* getEpCtl() { return ep_ctl; } + +private: + INTERFACE intf[MAX_INTF]; + uint8_t hub_nb; + uint8_t port; uint16_t vid; uint16_t pid; uint8_t addr; + uint8_t device_class; + uint8_t device_subclass; + uint8_t proto; + bool lowSpeed; + bool enumerated; + uint8_t nb_interf; + USBEndpoint* ep_ctl; + void init(); };
--- a/USBHost/USBEndpoint.h Tue Jan 28 06:50:12 2014 +0000 +++ b/USBHost/USBEndpoint.h Fri Jan 31 13:45:07 2014 +0000 @@ -1,22 +1,54 @@ +/* mbed USBHost Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #pragma once #include "USBHostTypes.h" +#include "USBDeviceConnected.h" +class USBDeviceConnected; class USBEndpoint { public: - USBEndpoint() : data01_toggle(DATA0),address(0),MaxPacketSize(8) {} + USBEndpoint() : data01_toggle(DATA0),address(0),MaxPacketSize(8) { + dev = NULL; + } + void setDevice(USBDeviceConnected* _dev) { dev = _dev; } void setState(uint8_t st){}; // dummy + void setLengthTransferred(int len) { transferred = len; }; void setSize(int size) { MaxPacketSize = size; } + void setType(ENDPOINT_TYPE _type) { type = _type; }; void setAddress(uint8_t addr) { address = addr; } void setData01(uint8_t data01) { data01_toggle = data01; } + + USBDeviceConnected* getDevice() { return dev; } + ENDPOINT_TYPE getType() { return type; }; + int getLengthTransferred() { return transferred; } uint8_t getAddress(){ return address; }; int getSize() { return MaxPacketSize; } + ENDPOINT_DIRECTION getDir() { return (address & 0x80) ? IN : OUT; } uint8_t getData01() { return data01_toggle; } void toggleData01() { data01_toggle = (data01_toggle == DATA0) ? DATA1 : DATA0; } private: + ENDPOINT_TYPE type; + ENDPOINT_DIRECTION dir; + USBDeviceConnected* dev; uint8_t data01_toggle; // DATA0,DATA1 uint8_t address; + int transferred; int MaxPacketSize; };
--- a/USBHost/USBHALHost.cpp Tue Jan 28 06:50:12 2014 +0000 +++ b/USBHost/USBHALHost.cpp Fri Jan 31 13:45:07 2014 +0000 @@ -1,6 +1,5 @@ // Simple USBHost for FRDM-KL46Z #include "USBHALHost.h" -#include <algorithm> template <bool>struct CtAssert; template <>struct CtAssert<true> {}; @@ -16,8 +15,13 @@ #define USB_DBG_HEX(A,B) while(0) #endif +#ifdef _USB_TEST #define USB_TEST_ASSERT(A) while(!(A)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);}; #define USB_TEST_ASSERT_FALSE(A) USB_TEST_ASSERT(!(A)) +#else +#define USB_TEST_ASSERT(A) while(0) +#define USB_TEST_ASSERT_FALSE(A) while(0) +#endif #define BD_OWN_MASK (1<<7) #define BD_DATA01_MASK (1<<6) @@ -98,7 +102,7 @@ NVIC_SetVector(USB0_IRQn, (uint32_t)_usbisr); NVIC_EnableIRQ(USB0_IRQn); - wait_attach(); + bool lowSpeed = wait_attach(); for(int retry = 2; retry > 0; retry--) { // Enable RESET @@ -123,7 +127,7 @@ USB_ERREN_DMAERREN_MASK| USB_ERREN_BTSERREN_MASK; - if (enumeration()) { + if (addDevice(0, 0, lowSpeed)) { break; } USB_DBG("retry=%d", retry); @@ -131,27 +135,24 @@ } } -void USBHALHost::wait_attach() { +bool USBHALHost::wait_attach() { attach_done = false; USB0->INTEN = USB_INTEN_ATTACHEN_MASK; while(!attach_done); wait_ms(100); USB_TEST_ASSERT_FALSE(USB0->CTL & USB_CTL_SE0_MASK); - lowSpeed = (USB0->CTL & USB_CTL_JSTATE_MASK) ? false : true; - if (lowSpeed) { // low speed - USB0->ENDPOINT[0].ENDPT |= USB_ENDPT_HOSTWOHUB_MASK; - } - USB_DBG("lowSpeed=%d", lowSpeed); + root_lowSpeed = (USB0->CTL & USB_CTL_JSTATE_MASK) ? false : true; + return root_lowSpeed; } -void USBHALHost::setAddr(int _addr) { - USB0->ADDR = (lowSpeed ? USB_ADDR_LSEN_MASK : 0x00) | USB_ADDR_ADDR(_addr); +void USBHALHost::setAddr(int _addr, bool _lowSpeed) { + USB0->ADDR = (_lowSpeed ? USB_ADDR_LSEN_MASK : 0x00) | USB_ADDR_ADDR(_addr); } -void USBHALHost::setEndpoint(bool use_retry) { - USB0->ENDPOINT[0].ENDPT = (lowSpeed ? USB_ENDPT_HOSTWOHUB_MASK : 0x00)| +void USBHALHost::setEndpoint() { + USB0->ENDPOINT[0].ENDPT = (root_lowSpeed ? USB_ENDPT_HOSTWOHUB_MASK : 0x00)| + USB_ENDPT_RETRYDIS_MASK| USB_ENDPT_EPCTLDIS_MASK| - (use_retry ? 0x00 : USB_ENDPT_RETRYDIS_MASK)| USB_ENDPT_EPRXEN_MASK| USB_ENDPT_EPTXEN_MASK| USB_ENDPT_EPHSHK_MASK; @@ -163,9 +164,10 @@ } int USBHALHost::token_setup(USBEndpoint* ep, SETUP_PACKET* setup, uint16_t wLength) { + USBDeviceConnected* dev = ep->getDevice(); for(int retry = 0;; retry++) { token_ready(); - USB0->ENDPOINT[0].ENDPT = (lowSpeed ? USB_ENDPT_HOSTWOHUB_MASK : 0x00) | + USB0->ENDPOINT[0].ENDPT = (root_lowSpeed ? USB_ENDPT_HOSTWOHUB_MASK : 0x00) | USB_ENDPT_RETRYDIS_MASK| USB_ENDPT_EPRXEN_MASK| USB_ENDPT_EPTXEN_MASK| @@ -219,7 +221,7 @@ USB_TEST_ASSERT(ep->getData01() == LastStatus); ep->setData01(LastStatus == DATA0 ? DATA1 : DATA0); if (retry > 0) { - USB_DBG("len=%d retry=%d %02x", len, retry, prev_LastStatus); + //USB_DBG("len=%d retry=%d %02x", len, retry, prev_LastStatus); } return len; } else if (LastStatus == STALL) { @@ -395,12 +397,16 @@ } void debug_hex(uint8_t* buf, int size) { + int n = 0; for(int i = 0; i < size; i++) { fprintf(stderr, "%02x ", buf[i]); - if (i%16 == 15) { - fprintf(stderr, "\r\n"); + if (++n >= 16) { + fprintf(stderr, "\n"); + n = 0; } } - fprintf(stderr, "\r\n"); + if (n > 0) { + fprintf(stderr, "\n"); + } }
--- a/USBHost/USBHALHost.h Tue Jan 28 06:50:12 2014 +0000 +++ b/USBHost/USBHALHost.h Fri Jan 31 13:45:07 2014 +0000 @@ -49,10 +49,9 @@ protected: USBHALHost(); void init(); - virtual bool enumeration() = 0; - bool lowSpeed; - void setAddr(int addr); - void setEndpoint(bool use_retry = false); + virtual bool addDevice(int port, int hub, bool lowSpeed) = 0; + void setAddr(int addr, bool lowSpeed = false); + void setEndpoint(); void token_transfer_init(); int token_setup(USBEndpoint* ep, SETUP_PACKET* setup, uint16_t wLength = 0); int token_in(USBEndpoint* ep, uint8_t* data = NULL, int size = 0, int retryLimit = 10); @@ -64,7 +63,8 @@ void UsbIrqhandler(); __IO bool attach_done; __IO bool token_done; - void wait_attach(); + bool wait_attach(); + bool root_lowSpeed; ODD_EVEN tx_ptr; ODD_EVEN rx_ptr; static USBHALHost * instHost;
--- a/USBHost/USBHost.cpp Tue Jan 28 06:50:12 2014 +0000 +++ b/USBHost/USBHost.cpp Fri Jan 31 13:45:07 2014 +0000 @@ -20,8 +20,13 @@ #define USB_DBG_ERRSTAT() while(0) #endif +#ifdef _USB_TEST #define USB_TEST_ASSERT(A) while(!(A)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);}; #define USB_TEST_ASSERT_FALSE(A) USB_TEST_ASSERT(!(A)) +#else +#define USB_TEST_ASSERT(A) while(0) +#define USB_TEST_ASSERT_FALSE(A) while(0) +#endif #define USB_INFO(...) do{fprintf(stderr,__VA_ARGS__);}while(0); @@ -37,136 +42,190 @@ } USBHost::USBHost() { + DeviceLists_count = 0; } -/* virtual */ bool USBHost::enumeration() { - USBEndpoint* ep = &ep_ctl_in_out; - uint8_t desc[64]; - ep->setAddress(0); - ep->setSize(8); // max packet size - dev.addr = 0; +/* virtual */ bool USBHost::addDevice(int hub, int port, bool lowSpeed) { + USBDeviceConnected* dev = new USBDeviceConnected; + USBEndpoint* ep = new USBEndpoint; + ep->setDevice(dev); + dev->init(hub, port, lowSpeed); + dev->setAddress(0); + dev->setEpCtl(ep); + uint8_t desc[18]; wait_ms(100); - SETUP_PACKET setup_get_descriptor = {0x80, GET_DESCRIPTOR, 1<<8, 0, 0}; - int result = ControlRead(&setup_get_descriptor, desc, ep->getSize()); - if (result < ep->getSize()) { - USB_DBG("result=%d %02x", result, LastStatus); - USB_DBG_ERRSTAT(); - return false; - } - USB_DBG_HEX(desc, result); - USB_DBG_ERRSTAT(); + + int rc = controlRead(dev, 0x80, GET_DESCRIPTOR, 1<<8, 0, desc, 8); + USB_TEST_ASSERT(rc == USB_TYPE_OK); + USB_DBG_HEX(desc, 8); DeviceDescriptor* dev_desc = reinterpret_cast<DeviceDescriptor*>(desc); ep->setSize(dev_desc->bMaxPacketSize); - SETUP_PACKET setup_set_address = {0x00, SET_ADDRESS, 1, 0, 0}; - result = ControlWrite(&setup_set_address); - if (result < 0) { - USB_DBG("result=%d %02x", result, LastStatus); - USB_DBG_ERRSTAT(); - return false; - } + int new_addr = USBDeviceConnected::getNewAddress(); + rc = controlWrite(dev, 0x00, SET_ADDRESS, new_addr, 0, NULL, 0); + USB_TEST_ASSERT(rc == USB_TYPE_OK); + dev->setAddress(new_addr); wait_ms(100); - dev.addr = 1; + + rc = controlRead(dev, 0x80, GET_DESCRIPTOR, 1<<8, 0, desc, sizeof(desc)); + USB_TEST_ASSERT(rc == USB_TYPE_OK); + USB_DBG_HEX(desc, sizeof(desc)); - result = ControlRead(&setup_get_descriptor, desc, sizeof(desc)); - if (result < 8) { - USB_DBG("result=%d", result); - USB_DBG_ERRSTAT(); - return false; + dev->setVid(dev_desc->idVendor); + dev->setPid(dev_desc->idProduct); + dev->setClass(dev_desc->bDeviceClass); + USB_INFO("hub: %d port: %d speed: %s vid: %04x pid: %04x class: %02x addr: %d\n", + hub, port, (lowSpeed ? "low " : "full"), dev->getVid(), dev->getPid(), dev->getClass(), + dev->getAddress()); + + USB_TEST_ASSERT(DeviceLists_count < MAX_DEVICE_CONNECTED); + DeviceLists[DeviceLists_count++] = dev; + + if (dev->getClass() == HUB_CLASS) { + const int config = 1; + int rc = controlWrite(dev, 0x00, SET_CONFIGURATION, config, 0, NULL, 0); + USB_TEST_ASSERT(rc == USB_TYPE_OK); + wait_ms(100); + Hub(dev); } - USB_DBG_HEX(desc, result); - USB_DBG_ERRSTAT(); + return true; +} - dev.vid = dev_desc->idVendor; - dev.pid = dev_desc->idProduct; - USB_INFO("USB VID: %04x, PID: %04x\n", dev.vid, dev.pid); - if (dev_desc->bDeviceClass == HUB_CLASS) { - USB_INFO("USB hub not supported.\n\n"); - exit(1); +// enumerate a device with the control USBEndpoint +USB_TYPE USBHost::enumerate(USBDeviceConnected * dev, IUSBEnumerator* pEnumerator) +{ + if (dev->getClass() == HUB_CLASS) { // skip hub class + return USB_TYPE_OK; } + uint8_t desc[18]; + USB_TYPE rc = controlRead(dev, 0x80, GET_DESCRIPTOR, 1<<8, 0, desc, sizeof(desc)); + USB_TEST_ASSERT(rc == USB_TYPE_OK); + USB_DBG_HEX(desc, sizeof(desc)); + if (rc != USB_TYPE_OK) { + return rc; + } + DeviceDescriptor* dev_desc = reinterpret_cast<DeviceDescriptor*>(desc); + dev->setClass(dev_desc->bDeviceClass); + pEnumerator->setVidPid(dev->getVid(), dev->getPid()); - setup_get_descriptor.wValue = 2<<8; // config descriptor - result = ControlRead(&setup_get_descriptor, desc, 4); - if (result != 4) { - USB_DBG("result=%d", result); - USB_DBG_ERRSTAT(); - return false; - } + rc = controlRead(dev, 0x80, GET_DESCRIPTOR, 2<<8, 0, desc, 4); + USB_TEST_ASSERT(rc == USB_TYPE_OK); USB_DBG_HEX(desc, 4); - USB_DBG_ERRSTAT(); int TotalLength = desc[2]|desc[3]<<8; uint8_t* buf = new uint8_t[TotalLength]; - result = ControlRead(&setup_get_descriptor, buf, TotalLength); - if (result != TotalLength) { - USB_DBG("result=%d TotalLength=%d %02x", result, TotalLength, LastStatus); - USB_DBG_ERRSTAT(); - return false; + rc = controlRead(dev, 0x80, GET_DESCRIPTOR, 2<<8, 0, buf, TotalLength); + USB_TEST_ASSERT(rc == USB_TYPE_OK); + //USB_DBG_HEX(buf, TotalLength); + + // Parse the configuration descriptor + parseConfDescr(dev, buf, TotalLength, pEnumerator); + delete[] buf; + // only set configuration if not enumerated before + if (!dev->isEnumerated()) { + USB_DBG("Set configuration 1 on dev: %p", dev); + // sixth step: set configuration (only 1 supported) + int config = 1; + USB_TYPE res = controlWrite(dev, 0x00, SET_CONFIGURATION, config, 0, NULL, 0); + if (res != USB_TYPE_OK) { + USB_DBG("SET CONF FAILED"); + return res; + } + // Some devices may require this delay + wait_ms(100); + dev->setEnumerated(); + // Now the device is enumerated! + USB_DBG("dev %p is enumerated", dev); } - USB_DBG_HEX(buf, TotalLength); - USB_DBG_ERRSTAT(); + return USB_TYPE_OK; +} - for(int i = 0; i < TotalLength; ) { - int Length = buf[i]; - uint8_t DescriptorType = buf[i+1]; - if (DescriptorType == 0x05) { // endpoint - EndpointDescriptor* desc = reinterpret_cast<EndpointDescriptor*>(buf+i); - USBEndpoint* ep = NULL; - if (desc->bmAttributes == 0x03) { // interrupt - if (desc->bEndpointAddress & 0x80) { - ep = &ep_int_in; +// this method fills the USBDeviceConnected object: class,.... . It also add endpoints found in the descriptor. +void USBHost::parseConfDescr(USBDeviceConnected * dev, uint8_t * conf_descr, uint32_t len, IUSBEnumerator* pEnumerator) +{ + uint32_t index = 0; + uint32_t len_desc = 0; + uint8_t id = 0; + int nb_endpoints_used = 0; + USBEndpoint * ep = NULL; + uint8_t intf_nb = 0; + bool parsing_intf = false; + uint8_t current_intf = 0; + EndpointDescriptor* ep_desc; + + while (index < len) { + len_desc = conf_descr[index]; + id = conf_descr[index+1]; + switch (id) { + case CONFIGURATION_DESCRIPTOR: + USB_DBG("dev: %p has %d intf", dev, conf_descr[4]); + dev->setNbIntf(conf_descr[4]); + break; + case INTERFACE_DESCRIPTOR: + if(pEnumerator->parseInterface(conf_descr[index + 2], conf_descr[index + 5], conf_descr[index + 6], conf_descr[index + 7])) { + if (intf_nb++ <= MAX_INTF) { + current_intf = conf_descr[index + 2]; + dev->addInterface(current_intf, conf_descr[index + 5], conf_descr[index + 6], conf_descr[index + 7]); + nb_endpoints_used = 0; + USB_DBG("ADD INTF %d on device %p: class: %d, subclass: %d, proto: %d", current_intf, dev, conf_descr[index + 5],conf_descr[index + 6],conf_descr[index + 7]); + } else { + USB_DBG("Drop intf..."); + } + parsing_intf = true; + } else { + parsing_intf = false; } - } else if (desc->bmAttributes == 0x02) { // bulk - ep = (desc->bEndpointAddress & 0x80) ? &ep_bulk_in : &ep_bulk_out; - } - if (ep) { - ep->setAddress(desc->bEndpointAddress); - ep->setSize(desc->wMaxPacketSize); - } + break; + case ENDPOINT_DESCRIPTOR: + ep_desc = reinterpret_cast<EndpointDescriptor*>(conf_descr+index); + if (parsing_intf && (intf_nb <= MAX_INTF) ) { + if (nb_endpoints_used < MAX_ENDPOINT_PER_INTERFACE) { + ENDPOINT_TYPE type = (ENDPOINT_TYPE)(ep_desc->bmAttributes & 0x03); + ENDPOINT_DIRECTION dir = (ep_desc->bEndpointAddress & 0x80) ? IN : OUT; + if(pEnumerator->useEndpoint(current_intf, type, dir)) { + ep = new USBEndpoint; + ep->setDevice(dev); + ep->setType(type); + ep->setAddress(ep_desc->bEndpointAddress); + ep->setSize(ep_desc->wMaxPacketSize); + USB_DBG("ADD USBEndpoint %p, on interf %d on device %p", ep, current_intf, dev); + dev->addEndpoint(current_intf, ep); + nb_endpoints_used++; + } + } + } + break; + case HID_DESCRIPTOR: + //lenReportDescr = conf_descr[index + 7] | (conf_descr[index + 8] << 8); + break; + default: + break; } - USB_DBG_HEX(buf+i, Length); - i += Length; + index += len_desc; } - delete[] buf; - - // config = 1 - SETUP_PACKET setup_set_config = {0x00, SET_CONFIGURATION, 1, 0, 0}; - result = ControlWrite(&setup_set_config); - if (result < 0) { - USB_DBG("set config: %02x", LastStatus); - USB_DBG_ERRSTAT(); - if (lowSpeed && LastStatus == STALL) { // TODO: - wait_ms(100); - return true; - } - return false; - } - wait_ms(100); - return true; } USB_TYPE USBHost::controlRead(USBDeviceConnected* dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len) { SETUP_PACKET setup = {requestType, request, value, index}; - int result = ControlRead(&setup, buf, len); - USB_DBG2("result=%d %02x", result, LastStatus); + int result = ControlRead(dev, &setup, buf, len); + //USB_DBG2("result=%d %02x", result, LastStatus); return (result >= 0) ? USB_TYPE_OK : USB_TYPE_ERROR; } USB_TYPE USBHost::controlWrite(USBDeviceConnected* dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len) { SETUP_PACKET setup = {requestType, request, value, index}; - int result = ControlWrite(&setup, buf, len); + int result = ControlWrite(dev, &setup, buf, len); if (result >= 0) { return USB_TYPE_OK; } USB_DBG("result=%d %02x", result, LastStatus); - USB_DBG_ERRSTAT(); USB_DBG_HEX(buf, len); return USB_TYPE_ERROR; } USB_TYPE USBHost::bulkRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking) { USB_TEST_ASSERT(blocking); - int result = BulkRead(buf, len); + int result = BulkRead(ep, buf, len); if (result >= 0) { return USB_TYPE_OK; } @@ -176,7 +235,7 @@ USB_TYPE USBHost::bulkWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking) { USB_TEST_ASSERT(blocking); - int result = BulkWrite(buf, len); + int result = BulkWrite(ep, buf, len); if (result >= 0) { return USB_TYPE_OK; } @@ -184,18 +243,19 @@ return USB_TYPE_ERROR; } -USB_TYPE USBHost::interruptWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking) { - USB_TEST_ASSERT(blocking); - int result = InterruptRead(buf, len); +USB_TYPE USBHost::interruptRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking) { + int result = InterruptRead(ep, buf, len); if (result >= 0) { return USB_TYPE_OK; } return USB_TYPE_ERROR; } -int USBHost::ControlRead(SETUP_PACKET* setup, uint8_t* data, int size) { - USBEndpoint* ep = &ep_ctl_in_out; - setAddr(dev.addr); +int USBHost::ControlRead(USBDeviceConnected* dev, SETUP_PACKET* setup, uint8_t* data, int size) { + USB_TEST_ASSERT(dev); + USBEndpoint* ep = dev->getEpCtl(); + USB_TEST_ASSERT(ep); + setAddr(dev->getAddress(), dev->getSpeed()); token_setup(ep, setup, size); // setup stage if (LastStatus != ACK) { USB_DBG("setup %02x", LastStatus); @@ -220,16 +280,20 @@ if (result < 0) { USB_DBG("status token_out %02x", LastStatus); if (LastStatus == STALL) { + ep->setLengthTransferred(read_len); return read_len; } return result; } + ep->setLengthTransferred(read_len); return read_len; } -int USBHost::ControlWrite(SETUP_PACKET* setup, uint8_t* data, int size) { - USBEndpoint* ep = &ep_ctl_in_out; - setAddr(dev.addr); +int USBHost::ControlWrite(USBDeviceConnected* dev, SETUP_PACKET* setup, uint8_t* data, int size) { + USB_TEST_ASSERT(dev); + USBEndpoint* ep = dev->getEpCtl(); + USB_TEST_ASSERT(ep); + setAddr(dev->getAddress(), dev->getSpeed()); token_setup(ep, setup, size); // setup stage if (LastStatus != ACK) { USB_DBG("setup %02x", LastStatus); @@ -248,12 +312,15 @@ USB_DBG("result=%d %02x", result, LastStatus); //return result; } + ep->setLengthTransferred(write_len); return write_len; } -int USBHost::InterruptRead(uint8_t* data, int size) { - USBEndpoint* ep = &ep_int_in; - setAddr(dev.addr); +int USBHost::InterruptRead(USBEndpoint* ep, uint8_t* data, int size) { + USB_TEST_ASSERT(ep); + USBDeviceConnected* dev = ep->getDevice(); + USB_TEST_ASSERT(dev); + setAddr(dev->getAddress(), dev->getSpeed()); setEndpoint(); const int retryLimit = 0; int read_len = 0; @@ -267,7 +334,7 @@ } break; } - USB_DBG("token_in result=%d %02x", result, LastStatus); + //USB_DBG("token_in result=%d %02x", result, LastStatus); return result; } read_len += result; @@ -275,12 +342,15 @@ break; } } + ep->setLengthTransferred(read_len); return read_len; } -int USBHost::BulkRead(uint8_t* data, int size, int timeout_ms) { - USBEndpoint* ep = &ep_bulk_in; - setAddr(dev.addr); +int USBHost::BulkRead(USBEndpoint* ep, uint8_t* data, int size, int timeout_ms) { + USB_TEST_ASSERT(ep); + USBDeviceConnected* dev = ep->getDevice(); + USB_TEST_ASSERT(dev); + setAddr(dev->getAddress()); setEndpoint(); int retryLimit = (timeout_ms == 0) ? 0 : 10; int read_len = 0; @@ -295,7 +365,7 @@ } break; } - USB_DBG("token_in result=%d %02x", result, LastStatus); + //USB_DBG("token_in result=%d %02x", result, LastStatus); return result; } read_len += result; @@ -307,12 +377,15 @@ break; } } + ep->setLengthTransferred(read_len); return read_len; } -int USBHost::BulkWrite(const uint8_t* data, int size) { - USBEndpoint* ep = &ep_bulk_out; - setAddr(dev.addr); +int USBHost::BulkWrite(USBEndpoint* ep, const uint8_t* data, int size) { + USB_TEST_ASSERT(ep); + USBDeviceConnected* dev = ep->getDevice(); + USB_TEST_ASSERT(dev); + setAddr(dev->getAddress()); setEndpoint(); int write_len = 0; for(int n = 0; write_len < size; n++) { @@ -333,11 +406,18 @@ break; } } + ep->setLengthTransferred(write_len); return write_len; } int USBHost::IsochronousRead(USBEndpoint* ep, uint8_t* data, int size) { - setAddr(dev.addr); - return token_iso_in(ep, data, size); + USBDeviceConnected* dev = ep->getDevice(); + USB_TEST_ASSERT(dev); + setAddr(dev->getAddress()); + int result = token_iso_in(ep, data, size); + if (result >= 0) { + ep->setLengthTransferred(result); + } + return result; }
--- a/USBHost/USBHost.h Tue Jan 28 06:50:12 2014 +0000 +++ b/USBHost/USBHost.h Fri Jan 31 13:45:07 2014 +0000 @@ -3,10 +3,10 @@ #include "mbed.h" #include "USBHALHost.h" #include "USBDeviceConnected.h" +#include "IUSBEnumerator.h" +#include "USBHostConf.h" #include "USBEndpoint.h" -class IUSBEnumerator {}; // dummy - class USBHost : public USBHALHost { public: /** @@ -95,22 +95,63 @@ */ USB_TYPE interruptWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true); - int ControlRead(SETUP_PACKET* setup, uint8_t* data, int size); - int ControlWrite(SETUP_PACKET* setup, uint8_t* data = NULL, int size = 0); - int BulkRead(uint8_t* data, int size, int timeout_ms = -1); - int BulkWrite(const uint8_t* data, int size); - int InterruptRead(uint8_t* data, int size); + /** + * Enumerate a device. + * + * @param dev device which will be enumerated + * + * @returns status of the enumeration + */ + USB_TYPE enumerate(USBDeviceConnected * dev, IUSBEnumerator* pEnumerator); + + /** + * Get a device + * + * @param index index of the device which will be returned + * + * @returns pointer on the "index" device + */ + USBDeviceConnected * getDevice(uint8_t index) { + return (index < DeviceLists_count) ? DeviceLists[index] : NULL; + } + + /** + * register a driver into the host associated with a callback function called when the device is disconnected + * + * @param dev device + * @param intf interface number + * @param tptr pointer to the object to call the member function on + * @param mptr pointer to the member function to be called + */ + template<typename T> + void registerDriver(USBDeviceConnected * dev, uint8_t intf, T* tptr, void (T::*mptr)(void)) { + } + + int BulkRead(USBEndpoint*ep, uint8_t* data, int size, int timeout_ms = -1); int IsochronousRead(USBEndpoint*ep, uint8_t* data, int size); - USBDeviceConnected dev; - private: USBHost(); static USBHost* inst; - virtual bool enumeration(); - USBEndpoint ep_ctl_in_out; - USBEndpoint ep_int_in; - USBEndpoint ep_bulk_in; - USBEndpoint ep_bulk_out; + virtual bool addDevice(int hub, int port, bool lowSpeed); + void root_enumeration(USBDeviceConnected* dev); + void parseConfDescr(USBDeviceConnected* dev, uint8_t* conf_descr, uint32_t len, IUSBEnumerator* pEnumerator); + USBDeviceConnected* DeviceLists[MAX_DEVICE_CONNECTED]; + int DeviceLists_count; + + int ControlRead(USBDeviceConnected* dev, SETUP_PACKET* setup, uint8_t* data, int size); + int ControlWrite(USBDeviceConnected* dev, SETUP_PACKET* setup, uint8_t* data = NULL, int size = 0); + int BulkWrite(USBEndpoint*ep, const uint8_t* data, int size); + int InterruptRead(USBEndpoint*ep, uint8_t* data, int size); + + // USB HUB + bool Hub(USBDeviceConnected* dev); + int SetPortPower(USBDeviceConnected* dev, int port); + int ClearPortPower(USBDeviceConnected* dev, int port); + int PortReset(USBDeviceConnected* dev, int port); + int SetPortFeature(USBDeviceConnected* dev, int feature, int index); + int ClearPortFeature(USBDeviceConnected* dev, int feature, int index); + int SetPortReset(USBDeviceConnected* dev, int port); + int GetPortStatus(USBDeviceConnected* dev, int port, uint32_t* status); };
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/USBHostHub.cpp Fri Jan 31 13:45:07 2014 +0000 @@ -0,0 +1,128 @@ +#include "USBHost.h" + +#ifdef _USB_DBG +#define USB_DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");} while(0); +#define USB_DBG_HEX(A,B) debug_hex(A,B) +extern void debug_hex(uint8_t* buf, int size); +#else +#define USB_DBG(...) while(0) +#define USB_DBG_HEX(A,B) while(0) +#endif + +#ifdef _USB_TEST +#define USB_TEST_ASSERT(A) while(!(A)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);}; +#define USB_TEST_ASSERT_FALSE(A) USB_TEST_ASSERT(!(A)) +#else +#define USB_TEST_ASSERT(A) while(0) +#define USB_TEST_ASSERT_FALSE(A) while(0) +#endif + +#define PORT_CONNECTION 0 +#define PORT_ENABLE 1 +#define PORT_SUSPEND 2 +#define PORT_OVER_CURRENT 3 +#define PORT_RESET 4 +#define PORT_POWER 8 +#define PORT_LOW_SPEED 9 + +#define C_PORT_CONNECTION 16 +#define C_PORT_ENABLE 17 +#define C_PORT_SUSPEND 18 +#define C_PORT_OVER_CURRENT 19 +#define C_PORT_RESET 20 + +bool USBHost::Hub(USBDeviceConnected* dev) { + HubDescriptor hubdesc; + // get HUB descriptor + int rc = controlRead(dev, + USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS, + GET_DESCRIPTOR, + 0x29 << 8, 0, reinterpret_cast<uint8_t*>(&hubdesc), + sizeof(HubDescriptor)); + USB_TEST_ASSERT(rc == USB_TYPE_OK); + if (rc != USB_TYPE_OK) { + return false; + } + USB_DBG_HEX((uint8_t*)&hubdesc, sizeof(hubdesc)); + + uint32_t status; + rc = controlRead( dev, + 0xa0, 0, 0, 0, reinterpret_cast<uint8_t*>(&status), 4); + USB_TEST_ASSERT(rc == USB_TYPE_OK); + if (rc != USB_TYPE_OK) { + return false; + } + USB_DBG("HUB STATUS: %08X\n", status); + + for(int i = 1; i <= hubdesc.bNbrPorts; i++) { + SetPortPower(dev, i); // power on + wait_ms(hubdesc.bPwrOn2PwrGood*2); + uint32_t status; + GetPortStatus(dev, i, &status); + USB_DBG("port: %d status: %08X\n", i, status); + if (status & 0x010000) { // Connect Status Change, has changed + USB_TEST_ASSERT(status & 0x000001); + ClearPortFeature(dev, C_PORT_CONNECTION, i); + int lowSpeed = 0; + if (status & 0x0200) { + lowSpeed = 1; + } + PortReset(dev, i); + if (!addDevice(1, i, lowSpeed)) { + ClearPortPower(dev, i); // power off + } + } else { + ClearPortPower(dev, i); // power off + } + } + return false; +} + + +int USBHost::SetPortPower(USBDeviceConnected* dev, int port) +{ + return SetPortFeature(dev, PORT_POWER, port); +} + +int USBHost::ClearPortPower(USBDeviceConnected* dev, int port) +{ + return ClearPortFeature(dev, PORT_POWER, port); +} + +int USBHost::SetPortFeature(USBDeviceConnected* dev, int feature, int index) +{ + return controlWrite(dev, 0x23, SET_FEATURE,feature,index,0,0); +} + +int USBHost::ClearPortFeature(USBDeviceConnected* dev, int feature, int index) +{ + return controlWrite(dev, 0x23, CLEAR_FEATURE,feature,index,0,0); +} + +int USBHost::SetPortReset(USBDeviceConnected* dev, int port) +{ + return SetPortFeature(dev, PORT_RESET, port); +} + +int USBHost::GetPortStatus(USBDeviceConnected* dev, int port, uint32_t* status) +{ + return controlRead(dev, 0xa3, GET_STATUS, 0, port, (uint8_t*)status, 4); +} + +int USBHost::PortReset(USBDeviceConnected* dev, int port) +{ + USB_DBG("%p port=%d\n", this, port); + USB_TEST_ASSERT(port >= 1); + SetPortReset(dev, port); + // wait reset + for(int i = 0; i < 100; i++) { + uint32_t status; + GetPortStatus(dev, port, &status); + USB_DBG("RESET port: %d status: %08X\n", port, status); + if (status & 0x100000) { // Reset change , Reset complete + return USB_TYPE_OK; + } + wait_ms(5); + } + return USB_TYPE_ERROR; +}
--- a/USBHost/USBHostTypes.h Tue Jan 28 06:50:12 2014 +0000 +++ b/USBHost/USBHostTypes.h Fri Jan 31 13:45:07 2014 +0000 @@ -82,7 +82,9 @@ #define USB_RECIPIENT_INTERFACE 0x01 #define USB_RECIPIENT_ENDPOINT 0x02 -// -------------- USB Standard Requests -------------- +// -------------- USB Standard Requests -------------- +#define GET_STATUS 0x00 +#define SET_FEATURE 0x03 #define SET_ADDRESS 0x05 #define GET_DESCRIPTOR 0x06 #define SET_CONFIGURATION 0x09
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHostGPS/USBHostGPS.cpp Fri Jan 31 13:45:07 2014 +0000 @@ -0,0 +1,100 @@ +#include "USBHostGPS.h" + +#ifdef _USB_DBG +#define USB_DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");} while(0); +#define USB_DBG2(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");} while(0); +#define USB_DBG_HEX(A,B) debug_hex(A,B) +void debug_hex(uint8_t* buf, int size); +#else +#define USB_DBG(...) while(0) +#define USB_DBG2(...) while(0) +#define USB_DBG_HEX(A,B) while(0) +#endif + +#define USB_TEST_ASSERT(A) while(!(A)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);}; +#define USB_TEST_ASSERT_FALSE(A) USB_TEST_ASSERT(!(A)) + +#define USB_INFO(...) do{fprintf(stderr,__VA_ARGS__);}while(0); + + +USBHostGPS::USBHostGPS(int baud_) +{ + host = USBHost::getHostInst(); + init(); + baud = baud_; +} + +void USBHostGPS::init() { + dev = NULL; + bulk_in = NULL; + onUpdate = 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]\n", dev->getVid(), dev->getPid(), dev, gps_intf); + dev_connected = true; + return true; + } + } + } + init(); + return 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; +} +
--- a/USBHostGPS/USBHostGPS.h Tue Jan 28 06:50:12 2014 +0000 +++ b/USBHostGPS/USBHostGPS.h Fri Jan 31 13:45:07 2014 +0000 @@ -3,19 +3,61 @@ #define PL2303_SET_LINE_CODING 0x20 -class USBHostGPS { +class USBHostGPS : public IUSBEnumerator { public: - USBHostGPS(int baud = 38400) { - host = USBHost::getHostInst(); - // stop bit = 1, parity = none, 8bit - uint8_t data[] = {baud&0xff, baud>>8, baud>>16, baud>>24, 0x00, 0x00, 0x08}; - SETUP_PACKET setup = {0x21, PL2303_SET_LINE_CODING, 0, 0, 0}; - host->ControlWrite(&setup, data, sizeof(data)); + + /** + * 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) { + int result = host->BulkRead(bulk_in, (uint8_t*)data, size, timeout_ms); + return (result >= 0) ? bulk_in->getLengthTransferred() : 0; } - int readNMEA(char* data, int size) { - return host->BulkRead((uint8_t*)data, size); + void attachEvent(void (*ptr)(uint8_t* data, int size)) { + if (ptr != NULL) { + onUpdate = ptr; + } } + void poll() { + int result = host->BulkRead(bulk_in, buf, sizeof(buf), 0); + if (result >= 0) { + if (onUpdate) { + (*onUpdate)(buf, bulk_in->getLengthTransferred()); + } + } + } + +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 (*onUpdate)(uint8_t* data, int size); + uint8_t buf[64]; + int baud; + void init(); };
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHostHID/USBHostMouse.cpp Fri Jan 31 13:45:07 2014 +0000 @@ -0,0 +1,175 @@ +#include "USBHostMouse.h" + +#ifdef _USB_DBG +#define USB_DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");} while(0); +#define USB_DBG_HEX(A,B) debug_hex(A,B) +void debug_hex(uint8_t* buf, int size); +#else +#define USB_DBG(...) while(0) +#define USB_DBG_HEX(A,B) while(0) +#endif + +#define USB_TEST_ASSERT(A) while(!(A)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);}; +#define USB_TEST_ASSERT_FALSE(A) USB_TEST_ASSERT(!(A)) + +#define USB_INFO(...) do{fprintf(stderr,__VA_ARGS__);}while(0); + +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); + USB_DBG("int_in=%p", int_in); + if (!int_in) + break; + + USB_INFO("New Mouse device: VID:%04x PID:%04x [dev: %p - intf: %d]\n", 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; +} + +/*virtual*/ void USBHostMouse::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 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 +{ + USB_DBG("intf: %d class: %02x %02x %02x", intf_nb, intf_class, intf_subclass, intf_protocol); + 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 +{ + USB_DBG("intf_nb=%d type=%d dir=%d", intf_nb, type, dir); + + if (intf_nb == mouse_intf) { + if (type == INTERRUPT_ENDPOINT && dir == IN) { + mouse_device_found = true; + return true; + } + } + return false; +} + +#if 0 +void USBHostMouse::setup() { + dev = host->getDevice(0); + if (dev->getClass() == HUB_CLASS) { + for(int i = 1; ; i++) { + dev = host->getDevice(i); + if (dev == NULL) { + break; + } + if (enumeration(dev)) { + break; + } + } + USB_TEST_ASSERT(ep_int_in); + } else { + ep_int_in = NULL; + } +} + +bool USBHostMouse::enumeration(USBDeviceConnected* dev) { + // config descriptor + uint8_t desc[4]; + int rc = host->controlRead(dev, 0x80, GET_DESCRIPTOR, 2<<8, 0, desc, 4); + USB_TEST_ASSERT(rc == USB_TYPE_OK); + USB_DBG_HEX(desc, 4); + + int TotalLength = desc[2]|desc[3]<<8; + uint8_t* buf = new uint8_t[TotalLength]; + rc = host->controlRead(dev, 0x80, GET_DESCRIPTOR, 2<<8, 0, buf, TotalLength); + USB_TEST_ASSERT(rc == USB_TYPE_OK); + //USB_DBG_HEX(buf, TotalLength); + bool found = false; + for(int i = 0; i < TotalLength; ) { + int Length = buf[i]; + uint8_t DescriptorType = buf[i+1]; + if (DescriptorType == 0x04) { // interface + InterfaceDescriptor* desc = reinterpret_cast<InterfaceDescriptor*>(buf+i); + if (desc->bInterfaceClass == 0x03) { + found = true; + } + } else if (DescriptorType == 0x05) { // endpoint + EndpointDescriptor* desc = reinterpret_cast<EndpointDescriptor*>(buf+i); + if (desc->bmAttributes == 0x03 && + (desc->bEndpointAddress & 0x80)) { // interrupt in + ep_int_in = new USBEndpoint; + ep_int_in->setDevice(dev); + ep_int_in->setAddress(desc->bEndpointAddress); + ep_int_in->setSize(desc->wMaxPacketSize); + } + } + USB_DBG_HEX(buf+i, Length); + i += Length; + } + delete[] buf; + if (!found) { + return false; + } + int config = 1; + host->controlWrite(dev, 0x00, SET_CONFIGURATION, config, 0, NULL, 0); + wait_ms(100); + return true; +} +#endif +
--- a/USBHostHID/USBHostMouse.h Tue Jan 28 06:50:12 2014 +0000 +++ b/USBHostHID/USBHostMouse.h Fri Jan 31 13:45:07 2014 +0000 @@ -1,16 +1,88 @@ -// Simple USBHost Mouse for FRDM-KL46Z +/* mbed USBHost Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #include "USBHost.h" -class USBHostMouse { +class USBHostMouse : public IUSBEnumerator { public: - USBHostMouse() { - host = USBHost::getHostInst(); + + /** + * 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(); + + int readReport(uint8_t* data) { + int rc = host->interruptRead(dev, int_in, data, 4); + return rc == USB_TYPE_OK ? 4 : 0; } - int readReport(uint8_t* data) { - return host->InterruptRead(data, 4); + void attachEvent(void (*ptr)(uint8_t* data, int size)) { + if (ptr != NULL) { + onUpdate = ptr; + } } + void poll() { + USB_TYPE rc = host->interruptRead(dev, int_in, report, sizeof(report)); + if (rc == USB_TYPE_OK) { + if (onUpdate) { + (*onUpdate)(report, int_in->getLengthTransferred()); + } + } + } + +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 (*onUpdate)(uint8_t* data, int size); + 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(); };
--- a/USBHostMSD/USBHostMSD.cpp Tue Jan 28 06:50:12 2014 +0000 +++ b/USBHostMSD/USBHostMSD.cpp Fri Jan 31 13:45:07 2014 +0000 @@ -29,7 +29,6 @@ { host = USBHost::getHostInst(); init(); - report = &host->report; } void USBHostMSD::init() { @@ -40,22 +39,84 @@ dev_connected = false; blockSize = 0; blockCount = 0; - msd_intf = 1; //msd_intf = -1; + msd_intf = -1; msd_device_found = false; disk_init = false; dev_connected = false; nb_ep = 0; } - bool USBHostMSD::connected() { - return true; + return dev_connected; } bool USBHostMSD::connect() { - return true; + if (dev_connected) { + return true; + } + + for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) { + if ((dev = host->getDevice(i)) != NULL) { + + //USB_DBG("Trying to connect MSD device dev=%p\n", dev); + + if(host->enumerate(dev, this)) + break; + + if (msd_device_found) { + bulk_in = dev->getEndpoint(msd_intf, BULK_ENDPOINT, IN); + bulk_out = dev->getEndpoint(msd_intf, BULK_ENDPOINT, OUT); + + if (!bulk_in || !bulk_out) + continue; + + USB_INFO("New MSD device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, msd_intf); + dev->setName("MSD", msd_intf); + host->registerDriver(dev, msd_intf, this, &USBHostMSD::init); + + dev_connected = true; + return true; + } + } //if() + } //for() + init(); + return false; +} + +/*virtual*/ void USBHostMSD::setVidPid(uint16_t vid, uint16_t pid) +{ + USB_DBG2("vid:%04x pid:%04x", vid, pid); + // we don't check VID/PID for MSD driver +} + +/*virtual*/ bool USBHostMSD::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed +{ + USB_DBG2("intf: %d class: %02x %02x %02x", intf_nb, intf_class, intf_subclass, intf_protocol); + + if ((msd_intf == -1) && + (intf_class == MSD_CLASS) && + (intf_subclass == 0x06) && + (intf_protocol == 0x50)) { + msd_intf = intf_nb; + return true; + } + return false; +} + +/*virtual*/ bool USBHostMSD::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used +{ + USB_DBG2("intf_nb=%d type=%d dir=%d", intf_nb, type, dir); + if (intf_nb == msd_intf) { + if (type == BULK_ENDPOINT) { + nb_ep++; + if (nb_ep == 2) + msd_device_found = true; + return true; + } + } + return false; } int USBHostMSD::testUnitReady() {
--- a/USBHostMSD/USBHostMSD.h Tue Jan 28 06:50:12 2014 +0000 +++ b/USBHostMSD/USBHostMSD.h Fri Jan 31 13:45:07 2014 +0000 @@ -17,12 +17,18 @@ #ifndef USBHOSTMSD_H #define USBHOSTMSD_H -#if 0 +#if _USB_DBG #define USB_DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\r\n");} while(0); #else #define USB_DBG(...) while(0); #endif +#if 0 +#define USB_DBG2(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\r\n");} while(0); +#else +#define USB_DBG2(...) while(0); +#endif + #if 1 #define USB_INFO(...) do{fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\r\n");}while(0); #else @@ -36,7 +42,7 @@ /** * A class to communicate a USB flash disk */ -class USBHostMSD : public FATFileSystem { +class USBHostMSD : public IUSBEnumerator, public FATFileSystem { public: /** * Constructor @@ -59,8 +65,11 @@ */ bool connect(); - 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 // From FATFileSystem virtual int disk_initialize();