USB Host WAN Dongle library
Fork of USBHostWANDongle_bleedingedge by
Revision 2:a8b2d0cd9bbd, committed 2012-06-26
- 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
--- 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