USB Host WAN Dongle library

Fork of USBHostWANDongle_bleedingedge by Donatien Garnier

Files at this revision

API Documentation at this revision

Comitter:
donatien
Date:
Tue Jun 26 13:43:54 2012 +0000
Parent:
1:49df46e3295c
Child:
3:4394986752db
Commit message:
Test with multiple interfaces

Changed in this revision

USB3GModule/WANDongle.cpp Show annotated file Show diff for this revision Revisions of this file
USB3GModule/WANDongle.h Show annotated file Show diff for this revision Revisions of this file
USB3GModule/WANDongleInitializer.cpp Show annotated file Show diff for this revision Revisions of this file
USB3GModule/WANDongleInitializer.h Show annotated file Show diff for this revision Revisions of this file
USB3GModule/WANDongleSerialPort.cpp Show annotated file Show diff for this revision Revisions of this file
USB3GModule/WANDongleSerialPort.h Show annotated file Show diff for this revision Revisions of this file
USBHost/USBDeviceConnected.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost/USBDeviceConnected.h Show annotated file Show diff for this revision Revisions of this file
--- a/USB3GModule/WANDongle.cpp	Fri May 25 09:31:41 2012 +0000
+++ b/USB3GModule/WANDongle.cpp	Tue Jun 26 13:43:54 2012 +0000
@@ -26,15 +26,9 @@
 #include "rtos.h"
 
 #include "WANDongle.h"
-
-//TODO refactor
+#include "WANDongleInitializer.h"
 
-//Huawei K3770 (Vodafone)
-uint8_t vodafone_k3770_switch_packet[] = {
-    0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78, 0, 0, 0, 0, 0, 0, 0, 0x11, 0x06, 0x20, 0, 0, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
-WANDongle::WANDongle() : cb_tx_en(false), cb_rx_en(false), listener(NULL)
+WANDongle::WANDongle() : cb_tx_en(false), cb_rx_en(false), listener(NULL), m_serialCount(0)
 {
     host = USBHost::getHostInst();
     init();
@@ -59,385 +53,69 @@
 
   host->lock();
 
-  for (int i = 0; i < MAX_DEVICE_NB; i++) {
-      if ((dev = host->getDevice(i)) != NULL) {
-
+  for (int i = 0; i < MAX_DEVICE_NB; i++)
+  {
+      if ((dev = host->getDevice(i)) != NULL)
+      {
           DBG("Found one device, reset it");
           host->resetDevice(dev);
 
           DBG("Enumerate");
           host->enumerate(dev);
-
-          //Vodafone K3770
-          if ((dev->getVid() == 0x12D1) && (dev->getPid() == 0x14D1)) {
+          
+          WANDongleInitializer* initializer = getInitializers();
+          
+          while(initializer++)
+          {
+            if ((dev->getVid() == initializer->getSerialVid()) && (dev->getPid() == initializer->getSerialPid()))
+            {
+              host->registerDriver(dev, 0, this, &WANDongle::init);
+              m_serialCount = initializer->getSerialPortCount();
+              for(int j = 0; j < m_serialCount; j++)
+              {
+                m_serial[j].connect( initializer->getEp(dev, j, false), initializer->getEp(dev, j, true) );
+              }
+              dev_connected = true;
+              host->unlock();
+              return true;
+            }
+            else if ((dev->getVid() == initializer->getMSDVid()) && (dev->getPid() == initializer->getMSDPid()))
+            {
               DBG("Vodafone K3370 dongle detected in MSD mode");
-
-              for (int j = 0; j < dev->getNbInterface(); j++) {
-
-                  if (dev->getInterface(j)->intf_class == MSD_CLASS) {
-
-                      if ( (bulk_out = dev->getEndpoint(j, BULK_ENDPOINT, OUT)) != NULL )  {
-
-                          DBG("MSD descriptor found on device %p, intf %d, will now try to switch into serial mode", (void *)dev, j);
-
-                          host->bulkWrite(dev, (Endpoint *)bulk_out, vodafone_k3770_switch_packet, 31);
-
-                          DBG("Switch packet sent");
-                          host->unlock();
-
-
-                          Thread::wait(500); //Not in a thread
-
-                          //Not wait for the dongle to reconnect
-                          while (1) {
-
-                              if (found) {
-                                  break;
-                              }
-
-                              Thread::wait(100);
-
-                              host->lock();
-
-
-                              for (int i = 0; i < MAX_DEVICE_NB; i++) {
-                                  if ((dev = host->getDevice(i)) != NULL) {
-                                      host->resetDevice(dev);
-                                      host->enumerate(dev);
-                                      
-                                      DBG("Found one device with vid: %04x pid: %04x", dev->getVid(), dev->getPid());
-
-                                      //Vodafone K3770
-                                      if ((dev->getVid() == 0x12D1) && (dev->getPid() == 0x14C9)) {
-                                          DBG("Switched successfully");
-                                          found = true;
-                                          break;
-                                      }
-                                  }
-                              }
-
-                              host->unlock();
-
-                          }
-                          host->lock();
-
-                          if (fetchEndpoints()) {
-                            DBG("ep: %p, %p\r\n", bulk_in, bulk_out);
-                            max_out_size = bulk_out->getSize();
-                            if( max_out_size > WANDONGLE_MAX_OUTEP_SIZE )
-                            {
-                              max_out_size = WANDONGLE_MAX_OUTEP_SIZE;
-                            }
-                            host->unlock();
-                            return true;
-                          }
-                          host->unlock();
-                      }
-                  }
+              //Try to switch   
+              if( initializer->switchMode() )
+              {
+                DBG("Switched OK");
+                host->unlock();
+                return false; //Will be connected on a next iteration
               }
-          } else if ((dev->getVid() == 0x12D1) && (dev->getPid() == 0x14C9)) {
-              if (fetchEndpoints()) {
-                DBG("ep: %p, %p\r\n", bulk_in, bulk_out);
-                max_out_size = bulk_out->getSize();
-                if( max_out_size > WANDONGLE_MAX_OUTEP_SIZE )
-                {
-                  max_out_size = WANDONGLE_MAX_OUTEP_SIZE;
-                }
+              else
+              {
+                ERR("Could not switch mode");
                 host->unlock();
-                return true;
+                return false;
               }
-          }
-      }
-  }
+            }
+          } //while()
+      } //if()
+  } //for()
   host->unlock();
-  bulk_in = NULL;
-  bulk_out = NULL;
-  dev_connected = false;
   return false;
 }
 
-int WANDongle::readPacket()
-{
-  rx_mtx.lock();
-  if(lock_rx)
-  {
-    ERR("Fail");
-    rx_mtx.unlock();
-    return -1;
-  }
-
-  lock_rx = true; //Receiving
-  rx_mtx.unlock();
-//  DBG("readPacket");
-  //lock_rx.lock();
-  host->lock();
-  USB_TYPE res = host->bulkRead(dev, (Endpoint *)bulk_in, buf_in, ((Endpoint *)bulk_in)->getSize(), false); //Queue transfer
-  if(res != USB_TYPE_PROCESSING)
-  {
-    host->unlock();
-    //lock_rx.unlock();
-    ERR("host->bulkRead() returned %d", res);
-    Thread::wait(100);
-    return -1;
-  }
-  host->unlock();
-  return 0;
-}
-
-int WANDongle::writePacket()
+IUSBHostSerial* WANDongle::getSerial(int index)
 {
-  tx_mtx.lock();
-  if(lock_tx)
-  {
-    ERR("Fail");
-    tx_mtx.unlock();
-    return -1;
-  }
-
-  lock_tx = true; //Transmitting
-  tx_mtx.unlock();
-//  DBG("writePacket");
-
-  //lock_tx.lock();
-  host->lock();
-  USB_TYPE res = host->bulkWrite(dev, (Endpoint *)bulk_out, buf_out, buf_out_len, false); //Queue transfer
-  if(res != USB_TYPE_PROCESSING)
-  {
-    host->unlock();
-    //lock_tx.unlock();
-    ERR("host->bulkWrite() returned %d", res);
-    Thread::wait(100);
-    return -1;
-  }
-  host->unlock();
-  return 0;
-}
-
-int WANDongle::putc(int c)
-{
-  tx_mtx.lock();
-  if(!lock_tx)
-  {
-    if(buf_out_len < max_out_size)
-    {
-      buf_out[buf_out_len] = (uint8_t)c;
-      buf_out_len++;
-    }
-  }
-  else
-  {
-    ERR("CAN'T WRITE!");
-  }
-  tx_mtx.unlock();
-  return c;
+  return m_serial[index];
 }
 
-int WANDongle::getc()
-{
-  rx_mtx.lock();
-  int c = 0;
-  if(!lock_rx)
-  {
-    if(buf_in_read_pos < buf_in_len)
-    {
-      c = (int)buf_in[buf_in_read_pos];
-      buf_in_read_pos++;
-    }
-  }
-  else
-  {
-    ERR("CAN'T READ!");
-  }
-  rx_mtx.unlock();
-  return c;
-}
-
-int WANDongle::readable()
-{
-  rx_mtx.lock();
-  if (lock_rx)
-  {
-    rx_mtx.unlock();
-    return 0;
-  }
-
- /* if( !lock_rx.trylock() )
-  {
-    return 0;
-  }*/
-  int res = buf_in_len - buf_in_read_pos;
-  //lock_rx.unlock();
-  rx_mtx.unlock();
-  return res;
-}
-
-int WANDongle::writeable()
+int WANDongle::getSerialCount()
 {
-  tx_mtx.lock();
-  if (lock_tx)
-  {
-    tx_mtx.unlock();
-    return 0;
-  }
-
-  /*if( !lock_tx.trylock() )
-  {
-    return 0;
-  }*/
-  int res = max_out_size - buf_out_len;
-  tx_mtx.unlock();
- //lock_tx.unlock();
-  return res;
-}
-
-void WANDongle::attach(IUSBHostSerialListener* pListener)
-{
-  if(pListener == NULL)
-  {
-    setupIrq(false, RxIrq);
-    setupIrq(false, TxIrq);
-  }
-  listener = pListener;
-  if(pListener != NULL)
-  {
-    setupIrq(true, RxIrq);
-    setupIrq(true, TxIrq);
-  }
-}
-
-void WANDongle::setupIrq(bool en, IrqType irq /*= RxIrq*/)
-{
-  switch(irq)
-  {
-  case RxIrq:
-    rx_mtx.lock();
-    cb_rx_en = en;
-    if(en && cb_rx_pending)
-    {
-      cb_rx_pending = false;
-      rx_mtx.unlock();
-      listener->readable(); //Process the interrupt that was raised
-    }
-    else
-    {
-      rx_mtx.unlock();
-    }
-    break;
-  case TxIrq:
-    tx_mtx.lock();
-    cb_tx_en = en;
-    if(en && cb_tx_pending)
-    {
-      cb_tx_pending = false;
-      tx_mtx.unlock();
-      listener->writeable(); //Process the interrupt that was raised
-    }
-    else
-    {
-      tx_mtx.unlock();
-    }
-    break;
-  }
+  return m_serialCount;
 }
 
 //Private methods
-
 void WANDongle::init()
 {
   dev_connected = false;
-
-  bulk_in = NULL;
-  bulk_out = NULL;
-
-  buf_out_len = 0;
-  lock_tx = false;
-  cb_tx_en = false;
-  cb_tx_pending = false;
-
-  buf_in_len = 0;
-  buf_in_read_pos = 0;
-  lock_rx = false;
-  cb_rx_en = false;
-  cb_rx_pending = false;
-
-}
-
-bool WANDongle::fetchEndpoints()
-{
-  bulk_in = dev->getEndpoint(0, BULK_ENDPOINT, IN);
-  bulk_out = dev->getEndpoint(0, BULK_ENDPOINT, OUT);
-  if ((bulk_in != NULL) && (bulk_out != NULL))
-  {
-
-    DBG("SERIAL FOUND on device %p, intf %d, bulk_in: %p, bulk_out: %p\r\n",
-        (void *)dev, 0, (void *)bulk_in, (void *)bulk_out);
-
-    bulk_in->attach(this, &WANDongle::rxHandler);
-    bulk_out->attach(this, &WANDongle::txHandler);
-    host->lock();
-    host->registerDriver(dev, 0, this, &WANDongle::init);
-    host->unlock();
-    dev_connected = true;
-
-    readPacket(); //Start receiving data
-
-    return true;
-  }
-  return false;
 }
 
-void WANDongle::rxHandler()
-{
-  if (((Endpoint *) bulk_in)->getState() == USB_TYPE_IDLE) //Success
-  {
-    buf_in_read_pos = 0;
-    buf_in_len = ((Endpoint *) bulk_in)->getLengthTransferred(); //Update length
-    //lock_rx.unlock();
-    rx_mtx.lock();
-    lock_rx = false; //Transmission complete
-    if(cb_rx_en)
-    {
-      rx_mtx.unlock();
-      listener->readable(); //Call handler from the IRQ context
-      //readPacket() should be called by the handler subsequently once the buffer has been emptied
-    }
-    else
-    {
-      cb_rx_pending = true; //Queue the callback
-      rx_mtx.unlock();
-    }
-
-  }
-  else //Error, try reading again
-  {
-    //lock_rx.unlock();
-    readPacket();
-  }
-}
-
-void WANDongle::txHandler()
-{
-  if (((Endpoint *) bulk_out)->getState() == USB_TYPE_IDLE) //Success
-  {
-    tx_mtx.lock();
-    buf_out_len = 0; //Reset length
-    lock_tx = false; //Transmission complete
-    //lock_tx.unlock();
-    if(cb_tx_en)
-    {
-      tx_mtx.unlock();
-      listener->writeable(); //Call handler from the IRQ context
-      //writePacket() should be called by the handler subsequently once the buffer has been filled
-    }
-    else
-    {
-      cb_tx_pending = true; //Queue the callback
-      tx_mtx.unlock();
-    }
-  }
-  else //Error, try reading again
-  {
-    //lock_tx.unlock();
-    writePacket();
-  }
-}
--- a/USB3GModule/WANDongle.h	Fri May 25 09:31:41 2012 +0000
+++ b/USB3GModule/WANDongle.h	Tue Jun 26 13:43:54 2012 +0000
@@ -28,10 +28,12 @@
 #define WANDONGLE_MAX_OUTEP_SIZE 64
 #define WANDONGLE_MAX_INEP_SIZE 64
 
+#define WANDONGLE_MAX_SERIAL_PORTS 2
+
 /** A class to use a WAN (3G/LTE) access dongle
  *
  */
-class WANDongle : public IUSBHostSerial {
+class WANDongle {
 public:
     /*
     * Constructor
@@ -53,88 +55,19 @@
      * * @return true if connection was successful
      */
     bool tryConnect();
-
-    /*
-    * Get a char from the dongle's serial interface
-    */
-    virtual int getc();
-
-    /*
-    * Put a char to the dongle's serial interface
-    */
-    virtual int putc(int c);
     
-    //void test();
-
-    /*
-     *  Read a packet from the dongle's serial interface, to be called after multiple getc() calls
-     */
-    virtual int readPacket();
-
-    /*
-     *  Write a packet to the dongle's serial interface, to be called after multiple putc() calls
-     */
-    virtual int writePacket();
-
-    /**
-    * Check the number of bytes available.
-    *
-    * @returns the number of bytes available
-    */
-    virtual int readable();
-
-    /**
-    * Check the free space in output.
-    *
-    * @returns the number of bytes available
-    */
-    virtual int writeable();
-
-    /**
-     *  Attach a handler to call when a packet is received / when a packet has been transmitted.
-     *
-     *  @param pListener instance of the listener deriving from the IUSBHostSerialListener
-     */
-    virtual void attach(IUSBHostSerialListener* pListener);
-    
-    /**
-     * Enable or disable readable/writeable callbacks
-     */
-    virtual void setupIrq(bool en, IrqType irq = RxIrq);
-
+    IUSBHostSerial* getSerial(int index);
+    int getSerialCount();
     
 protected:
-    Endpoint * bulk_in;
-    Endpoint * bulk_out;
     USBHost * host;
     USBDeviceConnected * dev;
     bool dev_connected;
 
-    uint8_t buf_out[WANDONGLE_MAX_OUTEP_SIZE];
-    volatile uint32_t buf_out_len;
-    uint32_t max_out_size;
-    volatile bool lock_tx;
-    //Mutex lock_tx;
-    volatile bool cb_tx_en;
-    volatile bool cb_tx_pending;
-    Mutex tx_mtx;
-
-    uint8_t buf_in[WANDONGLE_MAX_INEP_SIZE];
-    volatile uint32_t buf_in_len;
-    volatile uint32_t buf_in_read_pos;
-    volatile bool lock_rx;
-    //Mutex lock_rx;
-    volatile bool cb_rx_en;
-    volatile bool cb_rx_pending;
-    Mutex rx_mtx;
+    void init();
     
-    IUSBHostSerialListener* listener;
-    
-    void init();
-    void rxHandler();
-    void txHandler();
-    bool fetchEndpoints();
-
+    WANDongleSerialPort m_serial[WANDONGLE_MAX_SERIAL_PORTS];
+    int m_serialCount;
 };
 
 #endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USB3GModule/WANDongleInitializer.cpp	Tue Jun 26 13:43:54 2012 +0000
@@ -0,0 +1,85 @@
+/* Copyright (c) 2010-2011 mbed.org, MIT License
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+* and associated documentation files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use, copy, modify, merge, publish,
+* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or
+* substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#define __DEBUG__ 4 //Maximum verbosity
+#ifndef __MODULE__
+#define __MODULE__ "WANDongleInitializer.cpp"
+#endif
+
+#include "dbg.h"
+
+#include <cstdint>
+using std::uint16_t;
+
+#include "WANDongleInitializer.h"
+
+WANDongleInitializer::WANDongleInitializer(USBHost* pHost) : m_pHost(pHost)
+{
+
+}
+
+WANDongleInitializer[] WANDongleInitializer::getInitializers()
+{
+  static VodafoneK3770Initializer vodafoneK3770;
+  const static WANDongleInitializer list[] = { &vodafoneK3770, NULL };
+  return list;
+}
+
+//Huawei K3770 (Vodafone)
+const static uint8_t vodafone_k3770_switch_packet[] = {
+    0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78, 0, 0, 0, 0, 0, 0, 0, 0x11, 0x06, 0x20, 0, 0, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+VodafoneK3770Initializer::VodafoneK3770Initializer(USBHost* pHost) : WANDongleInitializer(pHost)
+{
+  
+}
+
+uint16_t VodafoneK3770Initializer::getMSDVid()      { return 0x12D1; }
+uint16_t VodafoneK3770Initializer::getMSDPid()      { return 0x14D1; }
+
+uint16_t VodafoneK3770Initializer::getSerialVid()   { return 0x12D1; }
+uint16_t VodafoneK3770Initializer::getSerialPid()   { return 0x14C9; }
+
+bool VodafoneK3770Initializer::switchMode(USBDeviceConnected* pDev)
+{
+  for (int i = 0; i < pDev->getNbInterface(); i++) 
+  {
+    if (pDev->getInterface(j)->intf_class == MSD_CLASS)
+    {
+      Endpoint* pEp = pDev->getEndpoint(i, BULK_ENDPOINT, OUT);
+      if ( pEp != NULL ) 
+      {
+        DBG("MSD descriptor found on device %p, intf %d, will now try to switch into serial mode", (void *)pDev, i);
+        m_pHost->bulkWrite(pDev, pEp, vodafone_k3770_switch_packet, 31);
+        return true;
+      }  
+   }
+   return false;
+}
+
+Endpoint* VodafoneK3770Initializer::getEp(USBDeviceConnected* pDev, int serialPortNumber, bool tx)
+{
+  return dev->getEndpoint(0, BULK_ENDPOINT, tx?OUT:IN, serialPortNumber);
+}
+
+int VodafoneK3770Initializer::getSerialPortCount()
+{
+  return 3;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USB3GModule/WANDongleInitializer.h	Tue Jun 26 13:43:54 2012 +0000
@@ -0,0 +1,68 @@
+/* Copyright (c) 2010-2011 mbed.org, MIT License
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+* and associated documentation files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use, copy, modify, merge, publish,
+* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or
+* substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef WANDONGLEINITIALIZER_H
+#define WANDONGLEINITIALIZER_H
+
+#include <cstdint>
+using std::uint16_t;
+using std::uint32_t;
+
+#include "USBHost.h"
+
+class WANDongleInitializer
+{
+protected:
+    WANDongleInitializer(USBHost* pHost);
+    USBHost* m_pHost;
+    
+public:
+    virtual uint16_t getMSDVid() = 0;
+    virtual uint16_t getMSDPid() = 0;
+    
+    virtual uint16_t getSerialVid() = 0;
+    virtual uint16_t getSerialPid() = 0;
+    
+    virtual bool switchMode(USBDeviceConnected* pDev) = 0;
+    
+    virtual Endpoint* getEp(USBDeviceConnected* pDev, int serialPortNumber, bool tx) = 0;
+    
+    virtual int getSerialPortCount() = 0;
+    
+    static WANDongleInitializer[] getInitializers();
+};
+
+class VodafoneK3770Initializer : public WANDongleInitializer
+{
+public:
+    VodafoneK3770Initializer();
+    
+    virtual uint16_t getMSDVid();
+    virtual uint16_t getMSDPid();
+    
+    virtual uint16_t getSerialVid();
+    virtual uint16_t getSerialPid();
+    
+    virtual bool switchMode(USBDeviceConnected* pDev);
+    
+    virtual Endpoint* getEp(USBDeviceConnected* pDev, int serialPortNumber, bool tx);
+    
+    virtual int getSerialPortCount() = 0;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USB3GModule/WANDongleSerialPort.cpp	Tue Jun 26 13:43:54 2012 +0000
@@ -0,0 +1,317 @@
+/* Copyright (c) 2010-2011 mbed.org, MIT License
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+* and associated documentation files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use, copy, modify, merge, publish,
+* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or
+* substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#define __DEBUG__ 4 //Maximum verbosity
+#ifndef __MODULE__
+#define __MODULE__ "WANDongleSerialPort.cpp"
+#endif
+
+#include "dbg.h"
+#include <cstdint>
+#include "rtos.h"
+
+#include "WANDongleSerialPort.h"
+
+WANDongleSerialPort::WANDongleSerialPort() : cb_tx_en(false), cb_rx_en(false)
+{
+  reset();
+}
+
+void WANDongleSerialPort::init(USBHost* pHost)
+{
+  host = pHost;
+}
+
+void WANDongleSerialPort::reset()
+{
+  bulk_in = NULL;
+  bulk_out = NULL;
+
+  buf_out_len = 0;
+  max_out_size = 0;
+  lock_tx = false;
+  cb_tx_pending = false;
+
+  buf_in_len = 0;
+  buf_in_read_pos = 0;
+  lock_rx = false;
+  cb_rx_pending = false;
+}
+
+int WANDongleSerialPort::readPacket()
+{
+  rx_mtx.lock();
+  if(lock_rx)
+  {
+    ERR("Fail");
+    rx_mtx.unlock();
+    return -1;
+  }
+
+  lock_rx = true; //Receiving
+  rx_mtx.unlock();
+//  DBG("readPacket");
+  //lock_rx.lock();
+  host->lock();
+  USB_TYPE res = host->bulkRead(dev, (Endpoint *)bulk_in, buf_in, ((Endpoint *)bulk_in)->getSize(), false); //Queue transfer
+  if(res != USB_TYPE_PROCESSING)
+  {
+    host->unlock();
+    //lock_rx.unlock();
+    ERR("host->bulkRead() returned %d", res);
+    Thread::wait(100);
+    return -1;
+  }
+  host->unlock();
+  return 0;
+}
+
+int WANDongleSerialPort::writePacket()
+{
+  tx_mtx.lock();
+  if(lock_tx)
+  {
+    ERR("Fail");
+    tx_mtx.unlock();
+    return -1;
+  }
+
+  lock_tx = true; //Transmitting
+  tx_mtx.unlock();
+//  DBG("writePacket");
+
+  //lock_tx.lock();
+  host->lock();
+  USB_TYPE res = host->bulkWrite(dev, (Endpoint *)bulk_out, buf_out, buf_out_len, false); //Queue transfer
+  if(res != USB_TYPE_PROCESSING)
+  {
+    host->unlock();
+    //lock_tx.unlock();
+    ERR("host->bulkWrite() returned %d", res);
+    Thread::wait(100);
+    return -1;
+  }
+  host->unlock();
+  return 0;
+}
+
+int WANDongleSerialPort::putc(int c)
+{
+  tx_mtx.lock();
+  if(!lock_tx)
+  {
+    if(buf_out_len < max_out_size)
+    {
+      buf_out[buf_out_len] = (uint8_t)c;
+      buf_out_len++;
+    }
+  }
+  else
+  {
+    ERR("CAN'T WRITE!");
+  }
+  tx_mtx.unlock();
+  return c;
+}
+
+int WANDongleSerialPort::getc()
+{
+  rx_mtx.lock();
+  int c = 0;
+  if(!lock_rx)
+  {
+    if(buf_in_read_pos < buf_in_len)
+    {
+      c = (int)buf_in[buf_in_read_pos];
+      buf_in_read_pos++;
+    }
+  }
+  else
+  {
+    ERR("CAN'T READ!");
+  }
+  rx_mtx.unlock();
+  return c;
+}
+
+int WANDongleSerialPort::readable()
+{
+  rx_mtx.lock();
+  if (lock_rx)
+  {
+    rx_mtx.unlock();
+    return 0;
+  }
+
+ /* if( !lock_rx.trylock() )
+  {
+    return 0;
+  }*/
+  int res = buf_in_len - buf_in_read_pos;
+  //lock_rx.unlock();
+  rx_mtx.unlock();
+  return res;
+}
+
+int WANDongleSerialPort::writeable()
+{
+  tx_mtx.lock();
+  if (lock_tx)
+  {
+    tx_mtx.unlock();
+    return 0;
+  }
+
+  /*if( !lock_tx.trylock() )
+  {
+    return 0;
+  }*/
+  int res = max_out_size - buf_out_len;
+  tx_mtx.unlock();
+ //lock_tx.unlock();
+  return res;
+}
+
+void WANDongleSerialPort::attach(IUSBHostSerialListener* pListener)
+{
+  if(pListener == NULL)
+  {
+    setupIrq(false, RxIrq);
+    setupIrq(false, TxIrq);
+  }
+  listener = pListener;
+  if(pListener != NULL)
+  {
+    setupIrq(true, RxIrq);
+    setupIrq(true, TxIrq);
+  }
+}
+
+void WANDongleSerialPort::setupIrq(bool en, IrqType irq /*= RxIrq*/)
+{
+  switch(irq)
+  {
+  case RxIrq:
+    rx_mtx.lock();
+    cb_rx_en = en;
+    if(en && cb_rx_pending)
+    {
+      cb_rx_pending = false;
+      rx_mtx.unlock();
+      listener->readable(); //Process the interrupt that was raised
+    }
+    else
+    {
+      rx_mtx.unlock();
+    }
+    break;
+  case TxIrq:
+    tx_mtx.lock();
+    cb_tx_en = en;
+    if(en && cb_tx_pending)
+    {
+      cb_tx_pending = false;
+      tx_mtx.unlock();
+      listener->writeable(); //Process the interrupt that was raised
+    }
+    else
+    {
+      tx_mtx.unlock();
+    }
+    break;
+  }
+}
+
+
+void WANDongleSerialPort::connect( Endpoint* pInEp, Endpoint* pOutEp )
+{
+  bulk_in = pInEp;
+  bulk_out = pOutEp;
+  max_out_size = bulk_out->getSize();
+  if( max_out_size > WANDONGLE_MAX_OUTEP_SIZE )
+  {
+    max_out_size = WANDONGLE_MAX_OUTEP_SIZE;
+  }
+  bulk_in->attach(this, &WANDongleSerialPort::rxHandler);
+  bulk_out->attach(this, &WANDongleSerialPort::txHandler);
+  readPacket(); //Start receiving data
+}
+
+void WANDongleSerialPort::disconnect( )
+{
+    reset();
+}
+
+//Private methods
+
+
+void WANDongleSerialPort::rxHandler()
+{
+  if (((Endpoint *) bulk_in)->getState() == USB_TYPE_IDLE) //Success
+  {
+    buf_in_read_pos = 0;
+    buf_in_len = ((Endpoint *) bulk_in)->getLengthTransferred(); //Update length
+    //lock_rx.unlock();
+    rx_mtx.lock();
+    lock_rx = false; //Transmission complete
+    if(cb_rx_en)
+    {
+      rx_mtx.unlock();
+      listener->readable(); //Call handler from the IRQ context
+      //readPacket() should be called by the handler subsequently once the buffer has been emptied
+    }
+    else
+    {
+      cb_rx_pending = true; //Queue the callback
+      rx_mtx.unlock();
+    }
+
+  }
+  else //Error, try reading again
+  {
+    //lock_rx.unlock();
+    readPacket();
+  }
+}
+
+void WANDongleSerialPort::txHandler()
+{
+  if (((Endpoint *) bulk_out)->getState() == USB_TYPE_IDLE) //Success
+  {
+    tx_mtx.lock();
+    buf_out_len = 0; //Reset length
+    lock_tx = false; //Transmission complete
+    //lock_tx.unlock();
+    if(cb_tx_en)
+    {
+      tx_mtx.unlock();
+      listener->writeable(); //Call handler from the IRQ context
+      //writePacket() should be called by the handler subsequently once the buffer has been filled
+    }
+    else
+    {
+      cb_tx_pending = true; //Queue the callback
+      tx_mtx.unlock();
+    }
+  }
+  else //Error, try reading again
+  {
+    //lock_tx.unlock();
+    writePacket();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USB3GModule/WANDongleSerialPort.h	Tue Jun 26 13:43:54 2012 +0000
@@ -0,0 +1,125 @@
+/* Copyright (c) 2010-2011 mbed.org, MIT License
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+* and associated documentation files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use, copy, modify, merge, publish,
+* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or
+* substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef WANDONGLESERIALPORT_H
+#define WANDONGLESERIALPORT_H
+
+#include "USBHost.h"
+#include "IUSBHostSerial.h"
+
+#include "rtos.h"
+
+
+#define WANDONGLE_MAX_OUTEP_SIZE 64
+#define WANDONGLE_MAX_INEP_SIZE 64
+
+/** A class to use a WAN (3G/LTE) access dongle
+ *
+ */
+class WANDongle : public IUSBHostSerial {
+public:
+    /*
+    * Constructor
+    *
+    */
+    WANDongleSerialPort( );
+    
+    void init(USBHost* pHost);
+    
+    void connect( Endpoint* pInEp, Endpoint* pOutEp );
+    
+    void disconnect( );
+
+    /*
+    * Get a char from the dongle's serial interface
+    */
+    virtual int getc();
+
+    /*
+    * Put a char to the dongle's serial interface
+    */
+    virtual int putc(int c);
+
+    /*
+     *  Read a packet from the dongle's serial interface, to be called after multiple getc() calls
+     */
+    virtual int readPacket();
+
+    /*
+     *  Write a packet to the dongle's serial interface, to be called after multiple putc() calls
+     */
+    virtual int writePacket();
+
+    /**
+    * Check the number of bytes available.
+    *
+    * @returns the number of bytes available
+    */
+    virtual int readable();
+
+    /**
+    * Check the free space in output.
+    *
+    * @returns the number of bytes available
+    */
+    virtual int writeable();
+
+    /**
+     *  Attach a handler to call when a packet is received / when a packet has been transmitted.
+     *
+     *  @param pListener instance of the listener deriving from the IUSBHostSerialListener
+     */
+    virtual void attach(IUSBHostSerialListener* pListener);
+    
+    /**
+     * Enable or disable readable/writeable callbacks
+     */
+    virtual void setupIrq(bool en, IrqType irq = RxIrq);
+
+    
+protected:
+    Endpoint * bulk_in;
+    Endpoint * bulk_out;
+    USBHost * host;
+
+    uint8_t buf_out[WANDONGLE_MAX_OUTEP_SIZE];
+    volatile uint32_t buf_out_len;
+    uint32_t max_out_size;
+    volatile bool lock_tx;
+    volatile bool cb_tx_en;
+    volatile bool cb_tx_pending;
+    Mutex tx_mtx;
+
+    uint8_t buf_in[WANDONGLE_MAX_INEP_SIZE];
+    volatile uint32_t buf_in_len;
+    volatile uint32_t buf_in_read_pos;
+    volatile bool lock_rx;
+    volatile bool cb_rx_en;
+    volatile bool cb_rx_pending;
+    Mutex rx_mtx;
+    
+    IUSBHostSerialListener* listener;
+    
+    void reset();
+    
+    void rxHandler();
+    void txHandler();
+
+};
+
+#endif
--- a/USBHost/USBDeviceConnected.cpp	Fri May 25 09:31:41 2012 +0000
+++ b/USBHost/USBDeviceConnected.cpp	Tue Jun 26 13:43:54 2012 +0000
@@ -95,13 +95,20 @@
 
 
 
-Endpoint * USBDeviceConnected::getEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) {
+Endpoint * 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)) {
-            return intf[intf_nb].ep[i];
+            if(index)
+            {
+              index--;
+            }
+            else
+            {
+              return intf[intf_nb].ep[i];
+            }
         }
     }
     return NULL;
--- a/USBHost/USBDeviceConnected.h	Fri May 25 09:31:41 2012 +0000
+++ b/USBHost/USBDeviceConnected.h	Tue Jun 26 13:43:54 2012 +0000
@@ -55,11 +55,13 @@
     /*
     * Retrieve an endpoint by its TYPE and DIRECTION
     *
+    * @param intf_nb the interface on which to lookup the endpoint
     * @param type type of the endpoint looked for
     * @param direction of the endpoint looked for
+    * @param index the index of the endpoint whitin the interface
     * @returns pointer on the endpoint if found, NULL otherwise
     */
-    Endpoint * getEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir);
+    Endpoint * getEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir, uint8_t index = 0);
     
     /*
     * Retrieve an endpoint by its index