USB Host WAN Dongle library
Fork of USBHostWANDongle_bleedingedge by
Diff: USB3GModule/WANDongle.cpp
- Revision:
- 0:ae46a0638b2c
- Child:
- 1:49df46e3295c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USB3GModule/WANDongle.cpp Thu May 24 16:39:35 2012 +0000 @@ -0,0 +1,441 @@ +/* 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__ "WANDongle.cpp" +#endif + +#include "dbg.h" +#include <cstdint> +#include "rtos.h" + +#include "WANDongle.h" + +//TODO refactor + +//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) +{ + host = USBHost::getHostInst(); + init(); +} + + +bool WANDongle::connected() { + return dev_connected; +} + +bool WANDongle::tryConnect() +{ + bool found = false; + + //FIXME should run on USB thread + + DBG("Trying to connect device"); + + if (dev_connected) { + return true; + } + + host->lock(); + + 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)) { + DBG("Vodafone K3370 dongle detected!!!"); + + 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 FOUND on device %p, intf %d, WILL NOW SWITCH 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 + + // now wait for the new device connected......... :( + 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); + + //Vodafone K3770 + if ((dev->getVid() == 0x12D1) && (dev->getPid() == 0x14C9)) { + DBG("SWITCH MODE OK!!!!!!!!!!\r\n"); + 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(); + } + } + } + } 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; + } + host->unlock(); + return true; + } + } + } + } + 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() +{ + 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; +} + +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() +{ + 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; + } +} + +//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(); + } +}