USBHost library. NOTE: This library is only officially supported on the LPC1768 platform. For more information, please see the handbook page.

Dependencies:   FATFileSystem mbed-rtos

Dependents:   BTstack WallbotWii SD to Flash Data Transfer USBHost-MSD_HelloWorld ... more

Legacy Warning

This is an mbed 2 library. To learn more about mbed OS 5, visit the docs.

Pull requests against this repository are no longer supported. Please raise against mbed OS 5 as documented above.

Files at this revision

API Documentation at this revision

Comitter:
mbed_official
Date:
Mon Dec 16 09:00:18 2013 +0000
Parent:
18:37c948cf0dbf
Child:
20:8f510a2502ef
Commit message:
Synchronized with git revision 170ac6562b7b2b5bb43f8ecf82b2af18b37eeb9c

Full URL: https://github.com/mbedmicro/mbed/commit/170ac6562b7b2b5bb43f8ecf82b2af18b37eeb9c/

improve USB host library and cellular modem stack

Changed in this revision

USBHost/USBHostConf.h Show annotated file Show diff for this revision Revisions of this file
USBHost/dbg.h Show annotated file Show diff for this revision Revisions of this file
USBHostSerial/USBHostSerial.cpp Show annotated file Show diff for this revision Revisions of this file
USBHostSerial/USBHostSerial.h Show annotated file Show diff for this revision Revisions of this file
--- a/USBHost/USBHostConf.h	Thu Oct 17 10:15:19 2013 +0100
+++ b/USBHost/USBHostConf.h	Mon Dec 16 09:00:18 2013 +0000
@@ -49,7 +49,7 @@
 #define USBHOST_MOUSE               1
 
 /*
-* Enable USBHostSerial
+* Enable USBHostSerial or USBHostMultiSerial (if set > 1)
 */
 #define USBHOST_SERIAL              1
 
--- a/USBHost/dbg.h	Thu Oct 17 10:15:19 2013 +0100
+++ b/USBHost/dbg.h	Mon Dec 16 09:00:18 2013 +0000
@@ -18,17 +18,35 @@
 #define USB_DEBUG_H
 
 //Debug is disabled by default
-#define DEBUG 0
+#define DEBUG 3 /*INFO,ERR,WARN*/
 #define DEBUG_TRANSFER 0
 #define DEBUG_EP_STATE 0
 #define DEBUG_EVENT 0
 
-#if (DEBUG)
+#if (DEBUG > 3)
 #define USB_DBG(x, ...) std::printf("[USB_DBG: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
 #else
 #define USB_DBG(x, ...)
 #endif
 
+#if (DEBUG > 2)
+#define USB_INFO(x, ...) std::printf("[USB_INFO: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
+#else
+#define USB_INFO(x, ...)
+#endif
+
+#if (DEBUG > 1)
+#define USB_WARN(x, ...) std::printf("[USB_WARNING: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
+#else
+#define USB_WARN(x, ...)
+#endif
+
+#if (DEBUG > 0)
+#define USB_ERR(x, ...) std::printf("[USB_ERR: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
+#else
+#define USB_ERR(x, ...)
+#endif
+
 #if (DEBUG_TRANSFER)
 #define USB_DBG_TRANSFER(x, ...) std::printf("[USB_TRANSFER: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
 #else
@@ -41,9 +59,6 @@
 #define USB_DBG_EVENT(x, ...)
 #endif
 
-#define USB_INFO(x, ...) std::printf("[USB_INFO: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
-#define USB_WARN(x, ...) std::printf("[USB_WARNING: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
-#define USB_ERR(x, ...) std::printf("[USB_ERR: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
 
 #endif
 
--- a/USBHostSerial/USBHostSerial.cpp	Thu Oct 17 10:15:19 2013 +0100
+++ b/USBHostSerial/USBHostSerial.cpp	Mon Dec 16 09:00:18 2013 +0000
@@ -20,27 +20,17 @@
 
 #include "dbg.h"
 
-#define SET_LINE_CODING 0x20
+#define CHECK_INTERFACE(cls,subcls,proto) \
+        (((cls == 0xFF)         && (subcls == 0xFF) && (proto == 0xFF)) /* QUALCOM CDC */  || \
+         ((cls == SERIAL_CLASS) && (subcls == 0x00) && (proto == 0x00)) /* STANDARD CDC */ )
 
-USBHostSerial::USBHostSerial(): circ_buf() {
-    host = USBHost::getHostInst();
-    size_bulk_in = 0;
-    size_bulk_out = 0;
-    init();
-}
+#if (USBHOST_SERIAL <= 1)
 
-void USBHostSerial::init() {
-    dev = NULL;
-    bulk_in = NULL;
-    bulk_out = NULL;
+USBHostSerial::USBHostSerial() 
+{
+    host = USBHost::getHostInst();
+    ports_found = 0;
     dev_connected = false;
-    serial_intf = -1;
-    serial_device_found = false;
-    line_coding.baudrate = 9600;
-    line_coding.data_bits = 8;
-    line_coding.parity = None;
-    line_coding.stop_bits = 1;
-    circ_buf.flush();
 }
 
 bool USBHostSerial::connected()
@@ -48,49 +38,219 @@
     return dev_connected;
 }
 
+void USBHostSerial::disconnect(void)
+{
+    ports_found = 0;
+    dev = NULL;
+}
+
 bool USBHostSerial::connect() {
 
-    if (dev_connected) {
-        return true;
+    if (dev) 
+    {
+        for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) 
+        {
+            USBDeviceConnected* d = host->getDevice(i);
+            if (dev == d)
+                return true;
+        }
+        disconnect();
     }
-    for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
-        if ((dev = host->getDevice(i)) != NULL) {
+    for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) 
+    {
+        USBDeviceConnected* d = host->getDevice(i);
+        if (d != NULL) {
             
-            USB_DBG("Trying to connect serial device\r\n");
-
-            if(host->enumerate(dev, this))
+            USB_DBG("Trying to connect serial device \r\n");
+            if(host->enumerate(d, this))
                 break;
             
-            if (serial_device_found) {
-                bulk_in = dev->getEndpoint(serial_intf, BULK_ENDPOINT, IN);
-                bulk_out = dev->getEndpoint(serial_intf, BULK_ENDPOINT, OUT);
-                
-                if (!bulk_in || !bulk_out)
-                    break;
-                
-                USB_INFO("New Serial device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, serial_intf);
-                dev->setName("Serial", serial_intf);
-                host->registerDriver(dev, serial_intf, this, &USBHostSerial::init);
-                
-                baud(9600);
-                
-                size_bulk_in = bulk_in->getSize();
-                size_bulk_out = bulk_out->getSize();
-                
-                bulk_in->attach(this, &USBHostSerial::rxHandler);
-                bulk_out->attach(this, &USBHostSerial::txHandler);
-                
-                host->bulkRead(dev, bulk_in, buf, size_bulk_in, false);
-                dev_connected = true;
-                return true;
+            USBEndpoint* bulk_in  = d->getEndpoint(port_intf, BULK_ENDPOINT, IN);
+            USBEndpoint* bulk_out = d->getEndpoint(port_intf, BULK_ENDPOINT, OUT);
+            if (bulk_in && bulk_out)
+            {
+                USBHostSerialPort::connect(host,d,port_intf,bulk_in, bulk_out);
+                dev = d;
             }
         }
     }
-    init();
+    return dev != NULL;
+}
+
+/*virtual*/ void USBHostSerial::setVidPid(uint16_t vid, uint16_t pid)
+{
+    // we don't check VID/PID for MSD driver
+}
+
+/*virtual*/ bool USBHostSerial::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 ((ports_found < USBHOST_MAXSERIAL) && 
+        CHECK_INTERFACE(intf_class, intf_subclass, intf_protocol)) {
+        port_intf = intf_nb;
+        ports_found = true;
+        return true;
+    }
+    return false;
+}
+
+/*virtual*/ bool USBHostSerial::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
+{
+    if (ports_found && (intf_nb == port_intf)) {
+        if (type == BULK_ENDPOINT) 
+            return true;
+    }
     return false;
 }
 
-void USBHostSerial::rxHandler() {
+#else // (USBHOST_SERIAL > 1)
+
+//------------------------------------------------------------------------------
+
+USBHostMultiSerial::USBHostMultiSerial() 
+{
+    host = USBHost::getHostInst();
+    dev = NULL;
+    memset(ports, NULL, sizeof(ports));
+    ports_found = 0;
+    dev_connected = false;
+}
+
+USBHostMultiSerial::~USBHostMultiSerial()
+{
+    disconnect();
+}
+
+bool USBHostMultiSerial::connected()
+{
+    return dev_connected;
+}
+
+void USBHostMultiSerial::disconnect(void)
+{
+    for (int port = 0; port < USBHOST_SERIAL; port ++) 
+    {
+        if (ports[port])
+        {
+            delete ports[port];
+            ports[port] = NULL;
+        }
+    }
+    ports_found = 0;
+    dev = NULL;
+}
+
+bool USBHostMultiSerial::connect() {
+
+    if (dev) 
+    {
+        for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) 
+        {
+            USBDeviceConnected* d = host->getDevice(i);
+            if (dev == d)
+                return true;
+        }
+        disconnect();
+    }
+    for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) 
+    {
+        USBDeviceConnected* d = host->getDevice(i);
+        if (d != NULL) {
+            
+            USB_DBG("Trying to connect serial device \r\n");
+            if(host->enumerate(d, this))
+                break;
+            
+            for (int port = 0; port < ports_found; port ++) 
+            {
+                USBEndpoint* bulk_in  = d->getEndpoint(port_intf[port], BULK_ENDPOINT, IN);
+                USBEndpoint* bulk_out = d->getEndpoint(port_intf[port], BULK_ENDPOINT, OUT);
+                if (bulk_in && bulk_out)
+                {
+                    ports[port] = new USBHostSerialPort();
+                    if (ports[port])
+                    {
+                        ports[port]->connect(host,d,port_intf[port],bulk_in, bulk_out);
+                        dev = d;
+                    }
+                }
+            }
+        }
+    }
+    return dev != NULL;
+}
+
+/*virtual*/ void USBHostMultiSerial::setVidPid(uint16_t vid, uint16_t pid)
+{
+    // we don't check VID/PID for MSD driver
+}
+
+/*virtual*/ bool USBHostMultiSerial::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 ((ports_found < USBHOST_SERIAL) && 
+        CHECK_INTERFACE(intf_class, intf_subclass, intf_protocol)) {
+        port_intf[ports_found++] = intf_nb;
+        return true;
+    }
+    return false;
+}
+
+/*virtual*/ bool USBHostMultiSerial::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
+{
+    if ((ports_found > 0) && (intf_nb == port_intf[ports_found-1])) {
+        if (type == BULK_ENDPOINT) 
+            return true;
+    }
+    return false;
+}
+
+#endif
+
+//------------------------------------------------------------------------------
+
+#define SET_LINE_CODING 0x20
+
+USBHostSerialPort::USBHostSerialPort(): circ_buf() 
+{
+    init();
+}
+
+void USBHostSerialPort::init(void)
+{
+    host = NULL;
+    dev = NULL;
+    serial_intf = NULL;
+    size_bulk_in = 0;
+    size_bulk_out = 0;
+    bulk_in = NULL;
+    bulk_out = NULL;
+    line_coding.baudrate = 9600;
+    line_coding.data_bits = 8;
+    line_coding.parity = None;
+    line_coding.stop_bits = 1;
+    circ_buf.flush();
+}
+
+void USBHostSerialPort::connect(USBHost* _host, USBDeviceConnected * _dev, 
+        uint8_t _serial_intf, USBEndpoint* _bulk_in, USBEndpoint* _bulk_out)
+{
+    host = _host;
+    dev = _dev;
+    serial_intf = _serial_intf;
+    bulk_in = _bulk_in;
+    bulk_out = _bulk_out;
+    
+    USB_INFO("New Serial device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, serial_intf);
+    dev->setName("Serial", serial_intf);
+    host->registerDriver(dev, serial_intf, this, &USBHostSerialPort::init);
+    //baud(9600);
+    size_bulk_in = bulk_in->getSize();
+    size_bulk_out = bulk_out->getSize();
+    bulk_in->attach(this, &USBHostSerialPort::rxHandler);
+    bulk_out->attach(this, &USBHostSerialPort::txHandler);
+    host->bulkRead(dev, bulk_in, buf, size_bulk_in, false);
+}
+
+void USBHostSerialPort::rxHandler() {
     if (bulk_in) {
         int len = bulk_in->getLengthTransferred();
         if (bulk_in->getState() == USB_TYPE_IDLE) {
@@ -103,7 +263,7 @@
     }
 }
 
-void USBHostSerial::txHandler() {
+void USBHostSerialPort::txHandler() {
     if (bulk_out) {
         if (bulk_out->getState() == USB_TYPE_IDLE) {
             tx.call();
@@ -111,7 +271,7 @@
     }
 }
 
-int USBHostSerial::_putc(int c) {
+int USBHostSerialPort::_putc(int c) {
     if (bulk_out) {
         if (host->bulkWrite(dev, bulk_out, (uint8_t *)&c, 1) == USB_TYPE_OK) {
             return 1;
@@ -120,12 +280,12 @@
     return -1;
 }
 
-void USBHostSerial::baud(int baudrate) {
+void USBHostSerialPort::baud(int baudrate) {
     line_coding.baudrate = baudrate;
     format(line_coding.data_bits, (Parity)line_coding.parity, line_coding.stop_bits);
 }
 
-void USBHostSerial::format(int bits, Parity parity, int stop_bits) {
+void USBHostSerialPort::format(int bits, Parity parity, int stop_bits) {
     line_coding.data_bits = bits;
     line_coding.parity = parity;
     line_coding.stop_bits = (stop_bits == 1) ? 0 : 2;
@@ -137,7 +297,7 @@
                         0, serial_intf, (uint8_t *)&line_coding, 7);
 }
 
-int USBHostSerial::_getc() {
+int USBHostSerialPort::_getc() {
     uint8_t c = 0;
     if (bulk_in == NULL) {
         init();
@@ -148,37 +308,36 @@
     return c;
 }
 
+int USBHostSerialPort::writeBuf(const char* b, int s)
+{
+    int c = 0;
+    if (bulk_out) 
+    {
+        while (c < s)
+        {
+            int i = (s < size_bulk_out) ? s : size_bulk_out;
+            if (host->bulkWrite(dev, bulk_out, (uint8_t *)(b+c), i) == USB_TYPE_OK) 
+                c += i;
+        }
+    }
+    return s;
+}
 
-uint8_t USBHostSerial::available() {
+int USBHostSerialPort::readBuf(char* b, int s)
+{
+    int i = 0;
+    if (bulk_in) 
+    {
+        for (i = 0; i < s; )
+            b[i++] = getc();
+    }
+    return i;
+}
+
+uint8_t USBHostSerialPort::available() {
     return circ_buf.available();
 }
 
-/*virtual*/ void USBHostSerial::setVidPid(uint16_t vid, uint16_t pid)
-{
-    // we don't check VID/PID for MSD driver
-}
 
-/*virtual*/ bool USBHostSerial::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 ((serial_intf == -1) &&
-        (intf_class == SERIAL_CLASS) &&
-        (intf_subclass == 0x00) &&
-        (intf_protocol == 0x00)) {
-        serial_intf = intf_nb;
-        return true;
-    }
-    return false;
-}
-
-/*virtual*/ bool USBHostSerial::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
-{
-    if (intf_nb == serial_intf) {
-        if (type == BULK_ENDPOINT) {
-            serial_device_found = true;
-            return true;
-        }
-    }
-    return false;
-}
 
 #endif
--- a/USBHostSerial/USBHostSerial.h	Thu Oct 17 10:15:19 2013 +0100
+++ b/USBHostSerial/USBHostSerial.h	Mon Dec 16 09:00:18 2013 +0000
@@ -28,12 +28,12 @@
 /** 
  * A class to communicate a USB virtual serial port
  */
-class USBHostSerial : public IUSBEnumerator, public Stream {
+class USBHostSerialPort : public Stream {
 public:
     /**
     * Constructor
     */
-    USBHostSerial();
+    USBHostSerialPort();
 
     enum IrqType {
         RxIrq,
@@ -48,20 +48,9 @@
         Space
     };
 
-    /**
-    * Check if a virtual serial port is connected
-    *
-    * @returns true if a serial device is connected
-    */
-    bool connected();
-    
-    /**
-     * Try to connect a serial device
-     *
-     * @return true if connection was successful
-     */
-    bool connect();
-    
+    void connect(USBHost* _host, USBDeviceConnected * _dev, 
+        uint8_t _serial_intf, USBEndpoint* _bulk_in, USBEndpoint* _bulk_out);
+
     /**
     * Check the number of bytes available.
     *
@@ -111,34 +100,29 @@
     /** Set the transmission format used by the Serial port
      *
      *  @param bits The number of bits in a word (default = 8)
-     *  @param parity The parity used (USBHostSerial::None, USBHostSerial::Odd, USBHostSerial::Even, USBHostSerial::Mark, USBHostSerial::Space; default = USBHostSerial::None)
+     *  @param parity The parity used (USBHostSerialPort::None, USBHostSerialPort::Odd, USBHostSerialPort::Even, USBHostSerialPort::Mark, USBHostSerialPort::Space; default = USBHostSerialPort::None)
      *  @param stop The number of stop bits (1 or 2; default = 1)
      */
-    void format(int bits = 8, Parity parity = USBHostSerial::None, int stop_bits = 1);
-
+    void format(int bits = 8, Parity parity = USBHostSerialPort::None, int stop_bits = 1);
+    virtual int writeBuf(const char* b, int s);
+    virtual int readBuf(char* b, int s);
 
 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
-
     virtual int _getc();
     virtual int _putc(int c);
     
 private:
     USBHost * host;
     USBDeviceConnected * dev;
+
     USBEndpoint * bulk_in;
     USBEndpoint * bulk_out;
     uint32_t size_bulk_in;
     uint32_t size_bulk_out;
 
-    bool dev_connected;
-
     void init();
 
-    MtxCircBuffer<uint8_t, 64> circ_buf;
+    MtxCircBuffer<uint8_t, 128> circ_buf;
 
     uint8_t buf[64];
 
@@ -156,10 +140,91 @@
     FunctionPointer rx;
     FunctionPointer tx;
 
-    int serial_intf;
-    bool serial_device_found;
+    uint8_t serial_intf;
+};
+
+#if (USBHOST_SERIAL <= 1)
+
+class USBHostSerial : public IUSBEnumerator, public USBHostSerialPort 
+{
+public: 
+    USBHostSerial();
+    
+    /**
+     * Try to connect a serial device
+     *
+     * @return true if connection was successful
+     */
+    bool connect();
+    
+    void disconnect();
+
+    /**
+    * Check if a any serial port is connected
+    *
+    * @returns true if a serial device is connected
+    */
+    bool connected();
+  
+protected:
+    USBHost* host;
+    USBDeviceConnected* dev;
+    uint8_t port_intf;
+    int ports_found;
+
+    //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;
+};
+
+#else // (USBHOST_SERIAL > 1)
 
+class USBHostMultiSerial : public IUSBEnumerator {
+public: 
+    USBHostMultiSerial();
+    virtual ~USBHostMultiSerial();
+    
+    USBHostSerialPort* getPort(int port) 
+    { 
+        return port < USBHOST_SERIAL ? ports[port] : NULL; 
+    }
+
+    /**
+     * Try to connect a serial device
+     *
+     * @return true if connection was successful
+     */
+    bool connect();
+    
+    void disconnect();
+
+    /**
+    * Check if a any serial port is connected
+    *
+    * @returns true if a serial device is connected
+    */
+    bool connected();
+  
+protected:
+    USBHost* host;
+    USBDeviceConnected* dev;
+    USBHostSerialPort* ports[USBHOST_SERIAL];
+    uint8_t port_intf[USBHOST_SERIAL];
+    int ports_found;
+
+    //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;
 };
+#endif // (USBHOST_SERIAL <= 1)
 
 #endif