Initial import of USB3GModem in the USBHost library

In the future, USBHostConf.h should really reside in the project that
imports USBHost, not inside the USBHost library itself. Doing that now
though might break compatibility with projects that currently import
USBHost, so we need to figure out a better solution.
pull/93/head
Bogdan Marinescu 2013-10-16 15:45:25 +03:00
parent 6b23e0fad0
commit a0d9973cab
9 changed files with 1493 additions and 9 deletions

View File

@ -0,0 +1,91 @@
/* IUSBHostSerial.h */
/* Copyright (c) 2010-2012 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 IUSBHOSTSERIAL_H_
#define IUSBHOSTSERIAL_H_
/**
* Generic interface to abstract 3G dongles' impl
*/
#include "USBHostConf.h"
#ifdef USBHOST_3GMODULE
#include "IUSBHostSerialListener.h"
class IUSBHostSerial {
public:
enum IrqType {
RxIrq,
TxIrq
};
/*
* Get a char from the dongle's serial interface
*/
virtual int getc() = 0;
/*
* Put a char to the dongle's serial interface
*/
virtual int putc(int c) = 0;
/*
* Read a packet from the dongle's serial interface, to be called after multiple getc() calls
*/
virtual int readPacket() = 0;
/*
* Write a packet to the dongle's serial interface, to be called after multiple putc() calls
*/
virtual int writePacket() = 0;
/**
* Check the number of bytes available.
*
* @returns the number of bytes available
*/
virtual int readable() = 0;
/**
* Check the free space in output.
*
* @returns the number of bytes available
*/
virtual int writeable() = 0;
/**
* 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) = 0;
/**
* Enable or disable readable/writeable callbacks
*/
virtual void setupIrq(bool en, IrqType irq = RxIrq) = 0;
};
#endif /* USBHOST_3GMODULE */
#endif /* IUSBHOSTSERIAL_H_ */

View File

@ -0,0 +1,37 @@
/* IUSBHostSerialListener.h */
/* Copyright (c) 2010-2012 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 IUSBHOSTSERIALLISTENER_H_
#define IUSBHOSTSERIALLISTENER_H_
#include "USBHostConf.h"
#ifdef USBHOST_3GMODULE
class IUSBHostSerialListener
{
public:
virtual void readable() = 0; //Called when new data is available
virtual void writeable() = 0; //Called when new space is available
};
#endif /* USBHOST_3GMODULE */
#endif /* IUSBHOSTSERIALLISTENER_H_ */

View File

@ -0,0 +1,221 @@
/* Copyright (c) 2010-2012 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.
*/
#include "USBHostConf.h"
#ifdef USBHOST_3GMODULE
#define __DEBUG__ 0
#ifndef __MODULE__
#define __MODULE__ "WANDongle.cpp"
#endif
#include "core/dbg.h"
#include <cstdint>
#include "rtos.h"
#include "WANDongle.h"
#include "WANDongleInitializer.h"
WANDongle::WANDongle() : m_pInitializer(NULL), m_serialCount(0)
{
host = USBHost::getHostInst();
init();
}
bool WANDongle::connected() {
return dev_connected;
}
bool WANDongle::tryConnect()
{
//FIXME should run on USB thread
DBG("Trying to connect device");
if (dev_connected) {
return true;
}
m_pInitializer = NULL;
for (int i = 0; i < MAX_DEVICE_CONNECTED; i++)
{
if ((dev = host->getDevice(i)) != NULL)
{
m_pInitializer = NULL; //Will be set in setVidPid callback
DBG("Enumerate");
int ret = host->enumerate(dev, this);
if(ret)
{
return false;
}
DBG("Device has VID:%04x PID:%04x", dev->getVid(), dev->getPid());
if(m_pInitializer) //If an initializer has been found
{
DBG("m_pInitializer=%p", m_pInitializer);
DBG("m_pInitializer->getSerialVid()=%04x", m_pInitializer->getSerialVid());
DBG("m_pInitializer->getSerialPid()=%04x", m_pInitializer->getSerialPid());
if ((dev->getVid() == m_pInitializer->getSerialVid()) && (dev->getPid() == m_pInitializer->getSerialPid()))
{
DBG("The dongle is in virtual serial mode");
host->registerDriver(dev, 0, this, &WANDongle::init);
m_serialCount = m_pInitializer->getSerialPortCount();
if( m_serialCount > WANDONGLE_MAX_SERIAL_PORTS )
{
m_serialCount = WANDONGLE_MAX_SERIAL_PORTS;
}
for(int j = 0; j < m_serialCount; j++)
{
DBG("Connecting serial port #%d", j+1);
DBG("Ep %p", m_pInitializer->getEp(dev, j, false));
DBG("Ep %p", m_pInitializer->getEp(dev, j, true));
m_serial[j].connect( dev, m_pInitializer->getEp(dev, j, false), m_pInitializer->getEp(dev, j, true) );
}
DBG("Device connected");
dev_connected = true;
return true;
}
else if ((dev->getVid() == m_pInitializer->getMSDVid()) && (dev->getPid() == m_pInitializer->getMSDPid()))
{
DBG("Vodafone K3370 dongle detected in MSD mode");
//Try to switch
if( m_pInitializer->switchMode(dev) )
{
DBG("Switched OK");
return false; //Will be connected on a next iteration
}
else
{
ERR("Could not switch mode");
return false;
}
}
} //if()
} //if()
} //for()
return false;
}
bool WANDongle::disconnect()
{
dev_connected = false;
for(int i = 0; i < WANDONGLE_MAX_SERIAL_PORTS; i++)
{
m_serial[i].disconnect();
}
return true;
}
WAN_DONGLE_TYPE WANDongle::getDongleType()
{
if( m_pInitializer != NULL )
{
return m_pInitializer->getType();
}
else
{
return WAN_DONGLE_TYPE_UNKNOWN;
}
}
IUSBHostSerial& WANDongle::getSerial(int index)
{
return m_serial[index];
}
int WANDongle::getSerialCount()
{
return m_serialCount;
}
//Private methods
void WANDongle::init()
{
m_pInitializer = NULL;
dev_connected = false;
for(int i = 0; i < WANDONGLE_MAX_SERIAL_PORTS; i++)
{
m_serial[i].init(host);
}
}
/*virtual*/ void WANDongle::setVidPid(uint16_t vid, uint16_t pid)
{
//Load right initializer
WANDongleInitializer** initializer = WANDongleInitializer::getInitializers(host);
while(*initializer)
{
DBG("*initializer=%p", *initializer);
DBG("(*initializer)->getSerialVid()=%04x", (*initializer)->getSerialVid());
DBG("(*initializer)->getSerialPid()=%04x", (*initializer)->getSerialPid());
if ((dev->getVid() == (*initializer)->getSerialVid()) && (dev->getPid() == (*initializer)->getSerialPid()))
{
DBG("The dongle is in virtual serial mode");
m_pInitializer = *initializer;
break;
}
else if ((dev->getVid() == (*initializer)->getMSDVid()) && (dev->getPid() == (*initializer)->getMSDPid()))
{
DBG("Vodafone K3370 dongle detected in MSD mode");
m_pInitializer = *initializer;
break;
}
initializer++;
} //while()
if(m_pInitializer)
{
m_pInitializer->setVidPid(vid, pid);
}
}
/*virtual*/ bool WANDongle::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(m_pInitializer)
{
return m_pInitializer->parseInterface(intf_nb, intf_class, intf_subclass, intf_protocol);
}
else
{
return false;
}
}
/*virtual*/ bool WANDongle::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
{
if(m_pInitializer)
{
return m_pInitializer->useEndpoint(intf_nb, type, dir);
}
else
{
return false;
}
}
#endif /* USBHOST_3GMODULE */

View File

@ -0,0 +1,99 @@
/* Copyright (c) 2010-2012 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 WANDONGLE_H
#define WANDONGLE_H
#include "USBHostConf.h"
#ifdef USBHOST_3GMODULE
#include "USBHost.h"
#include "IUSBHostSerial.h"
#include "rtos.h"
#include "WANDongleSerialPort.h"
#include "WANDongleInitializer.h"
#include "IUSBEnumerator.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 IUSBEnumerator {
public:
/*
* Constructor
*
* @param rootdir mount name
*/
WANDongle();
/*
* Check if a serial port device is connected
*
* @return true if a serial device is connected
*/
bool connected();
/*
* Try to connect device
*
* * @return true if connection was successful
*/
bool tryConnect();
/*
* Disconnect device
*
* * @return true if disconnection was successful
*/
bool disconnect();
WAN_DONGLE_TYPE getDongleType();
IUSBHostSerial& getSerial(int index);
int getSerialCount();
//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
protected:
USBHost * host;
USBDeviceConnected * dev;
bool dev_connected;
WANDongleInitializer* m_pInitializer;
void init();
WANDongleSerialPort m_serial[WANDONGLE_MAX_SERIAL_PORTS];
int m_serialCount;
};
#endif /* USBHOST_3GMODULE */
#endif

View File

@ -0,0 +1,380 @@
/* Copyright (c) 2010-2012 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.
*/
#include "USBHostConf.h"
#ifdef USBHOST_3GMODULE
#define __DEBUG__ 0
#ifndef __MODULE__
#define __MODULE__ "WANDongleInitializer.cpp"
#endif
#include "core/dbg.h"
#include <cstdint>
using std::uint16_t;
#include "WANDongleInitializer.h"
WANDongleInitializer::WANDongleInitializer(USBHost* pHost) : m_pHost(pHost)
{
}
WANDongleInitializer** WANDongleInitializer::getInitializers(USBHost* pHost)
{
static VodafoneK3770Initializer vodafoneK3770(pHost);
static VodafoneK3772ZInitializer vodafoneK3772Z(pHost);
// mamm
static UbxInitializer ubx(pHost);
const static WANDongleInitializer* list[] = { &vodafoneK3770, &vodafoneK3772Z, &ubx, NULL };
// const static WANDongleInitializer* list[] = { &vodafoneK3770, &vodafoneK3772Z, NULL };
// mamm
return (WANDongleInitializer**)list;
}
//Huawei K3770 (Vodafone)
// Switching from mass storage device string is: "55 53 42 43 12 34 56 78 00 00 00 00 00 00 00 11 06 20 00 00 01 00 00 00 00 00 00 00 00 00 00"
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->getNbIntf(); i++)
{
if (pDev->getInterface(i)->intf_class == MSD_CLASS)
{
USBEndpoint* 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;
}
USBEndpoint* VodafoneK3770Initializer::getEp(USBDeviceConnected* pDev, int serialPortNumber, bool tx)
{
return pDev->getEndpoint(serialPortNumber, BULK_ENDPOINT, tx?OUT:IN, 0);
}
int VodafoneK3770Initializer::getSerialPortCount()
{
return 2;
}
/*virtual*/ void VodafoneK3770Initializer::setVidPid(uint16_t vid, uint16_t pid)
{
if( (vid == getSerialVid() ) && ( pid == getSerialPid() ) )
{
m_hasSwitched = true;
m_currentSerialIntf = 0;
m_endpointsToFetch = 4;
}
else
{
m_hasSwitched = false;
m_endpointsToFetch = 1;
}
}
/*virtual*/ bool VodafoneK3770Initializer::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( m_hasSwitched )
{
if( intf_class == 0xFF )
{
if( (m_currentSerialIntf == 0) || (m_currentSerialIntf == 4) )
{
m_currentSerialIntf++;
return true;
}
m_currentSerialIntf++;
}
}
else
{
if( (intf_nb == 0) && (intf_class == MSD_CLASS) )
{
return true;
}
}
return false;
}
/*virtual*/ bool VodafoneK3770Initializer::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
{
if( m_hasSwitched )
{
if( (type == BULK_ENDPOINT) && m_endpointsToFetch )
{
m_endpointsToFetch--;
return true;
}
}
else
{
if( (type == BULK_ENDPOINT) && (dir == OUT) && m_endpointsToFetch )
{
m_endpointsToFetch--;
return true;
}
}
return false;
}
/*virtual*/ WAN_DONGLE_TYPE VodafoneK3770Initializer::getType()
{
return WAN_DONGLE_TYPE_VODAFONEK3770;
}
// NVIDIA (ICERA) /ZTE K3772-Z (Vodafone)
// Switching from mass storage device string is: "55 53 42 43 12 34 56 78 00 00 00 00 00 00 06 1b 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00"
static uint8_t vodafone_k3772_z_switch_packet[] = {
0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78, 0, 0, 0, 0, 0, 0, 0x06, 0x1b, 0, 0, 0, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
VodafoneK3772ZInitializer::VodafoneK3772ZInitializer(USBHost* pHost) : WANDongleInitializer(pHost)
{
}
uint16_t VodafoneK3772ZInitializer::getMSDVid() { return 0x19D2; }
uint16_t VodafoneK3772ZInitializer::getMSDPid() { return 0x1179; }
uint16_t VodafoneK3772ZInitializer::getSerialVid() { return 0x19D2; }
uint16_t VodafoneK3772ZInitializer::getSerialPid() { return 0x1181; }
bool VodafoneK3772ZInitializer::switchMode(USBDeviceConnected* pDev)
{
for (int i = 0; i < pDev->getNbIntf(); i++)
{
if (pDev->getInterface(i)->intf_class == MSD_CLASS)
{
USBEndpoint* 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_k3772_z_switch_packet, 31);
return true;
}
}
}
return false;
}
USBEndpoint* VodafoneK3772ZInitializer::getEp(USBDeviceConnected* pDev, int serialPortNumber, bool tx)
{
return pDev->getEndpoint((serialPortNumber==1)?0:1, BULK_ENDPOINT, tx?OUT:IN, 0);
}
int VodafoneK3772ZInitializer::getSerialPortCount()
{
return 2;
}
/*virtual*/ void VodafoneK3772ZInitializer::setVidPid(uint16_t vid, uint16_t pid)
{
if( (vid == getSerialVid() ) && ( pid == getSerialPid() ) )
{
m_hasSwitched = true;
m_currentSerialIntf = 0;
m_endpointsToFetch = 4;
}
else
{
m_hasSwitched = false;
m_endpointsToFetch = 1;
}
}
/*virtual*/ bool VodafoneK3772ZInitializer::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( m_hasSwitched )
{
DBG("Interface #%d; Class:%02x; SubClass:%02x; Protocol:%02x", intf_nb, intf_class, intf_subclass, intf_protocol);
if( intf_class == 0x0A )
{
if( (m_currentSerialIntf == 0) || (m_currentSerialIntf == 1) )
{
m_currentSerialIntf++;
return true;
}
m_currentSerialIntf++;
}
}
else
{
if( (intf_nb == 0) && (intf_class == MSD_CLASS) )
{
return true;
}
}
return false;
}
/*virtual*/ bool VodafoneK3772ZInitializer::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
{
if( m_hasSwitched )
{
DBG("USBEndpoint on Inteface #%d; Type:%d; Direction:%d", intf_nb, type, dir);
if( (type == BULK_ENDPOINT) && m_endpointsToFetch )
{
m_endpointsToFetch--;
return true;
}
}
else
{
if( (type == BULK_ENDPOINT) && (dir == OUT) && m_endpointsToFetch )
{
m_endpointsToFetch--;
return true;
}
}
return false;
}
/*virtual*/ WAN_DONGLE_TYPE VodafoneK3772ZInitializer::getType()
{
return WAN_DONGLE_TYPE_VODAFONEK3772Z;
}
//-----------------------------------------------------------------------
// mamm, u-blox Modem
//-----------------------------------------------------------------------
UbxInitializer::UbxInitializer(USBHost* pHost) : WANDongleInitializer(pHost)
{
}
uint16_t UbxInitializer::getMSDVid() { return 0x1546; }
uint16_t UbxInitializer::getMSDPid() { return 0x0000; }
uint16_t UbxInitializer::getSerialVid() { return 0x1546; }
uint16_t UbxInitializer::getSerialPid() { return 0x1102; }
bool UbxInitializer::switchMode(USBDeviceConnected* pDev)
{
for (int i = 0; i < pDev->getNbIntf(); i++)
{
if (pDev->getInterface(i)->intf_class == MSD_CLASS)
{
USBEndpoint* pEp = pDev->getEndpoint(i, BULK_ENDPOINT, OUT);
if ( pEp != NULL )
{
ERR("MSD descriptor found on device %p, intf %d", (void *)pDev, i);
}
}
}
return false;
}
#define UBX_SERIALCOUNT 7
int UbxInitializer::getSerialPortCount()
{
return UBX_SERIALCOUNT;
}
/*virtual*/ void UbxInitializer::setVidPid(uint16_t vid, uint16_t pid)
{
if( (vid == getSerialVid() ) && ( pid == getSerialPid() ) )
{
m_hasSwitched = true;
m_currentSerialIntf = 0;
m_endpointsToFetch = UBX_SERIALCOUNT*2;
}
else
{
m_hasSwitched = false;
m_endpointsToFetch = 1;
}
}
/*virtual*/ bool UbxInitializer::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( m_hasSwitched )
{
DBG("Interface #%d; Class:%02x; SubClass:%02x; Protocol:%02x", intf_nb, intf_class, intf_subclass, intf_protocol);
if( intf_class == 0x0A )
{
if( (m_currentSerialIntf == 0) || (m_currentSerialIntf == 1) )
{
m_serialIntfMap[m_currentSerialIntf++] = intf_nb;
return true;
}
m_currentSerialIntf++;
}
}
else
{
if( (intf_nb == 0) && (intf_class == MSD_CLASS) )
{
return true;
}
}
return false;
}
/*virtual*/ bool UbxInitializer::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
{
if( m_hasSwitched )
{
DBG("USBEndpoint on Interface #%d; Type:%d; Direction:%d", intf_nb, type, dir);
if( (type == BULK_ENDPOINT) && m_endpointsToFetch )
{
m_endpointsToFetch--;
return true;
}
}
else
{
if( (type == BULK_ENDPOINT) && (dir == OUT) && m_endpointsToFetch )
{
m_endpointsToFetch--;
return true;
}
}
return false;
}
/*virtual*/ WAN_DONGLE_TYPE UbxInitializer::getType()
{
return WAN_DONGLE_TYPE_UBX;
}
#endif /* USBHOST_3GMODULE */

View File

@ -0,0 +1,178 @@
/* Copyright (c) 2010-2012 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 "USBHostConf.h"
#ifdef USBHOST_3GMODULE
#include <cstdint>
using std::uint16_t;
using std::uint32_t;
#include "USBHost.h"
#include "IUSBEnumerator.h"
enum WAN_DONGLE_TYPE
{
WAN_DONGLE_TYPE_UNKNOWN = -1,
WAN_DONGLE_TYPE_VODAFONEK3770 = 0,
WAN_DONGLE_TYPE_VODAFONEK3772Z = 1,
WAN_DONGLE_TYPE_UBX = 2,
};
#define WANDONGLE_MAX_SERIAL_PORTS 2
class WANDongleInitializer : public IUSBEnumerator
{
protected:
WANDongleInitializer(USBHost* pHost);
USBHost* m_pHost;
uint8_t m_serialIntfMap[WANDONGLE_MAX_SERIAL_PORTS];
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 USBEndpoint* getEp(USBDeviceConnected* pDev, int serialPortNumber, bool tx) {
return pDev->getEndpoint(m_serialIntfMap[serialPortNumber], BULK_ENDPOINT, tx ? OUT : IN, 0);
}
virtual int getSerialPortCount() = 0;
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
virtual WAN_DONGLE_TYPE getType() = 0;
virtual uint8_t getSerialIntf(int index) { return m_serialIntfMap[index]; }
static WANDongleInitializer** getInitializers(USBHost* pHost);
};
class VodafoneK3770Initializer : public WANDongleInitializer
{
public:
VodafoneK3770Initializer(USBHost* pHost);
virtual uint16_t getMSDVid();
virtual uint16_t getMSDPid();
virtual uint16_t getSerialVid();
virtual uint16_t getSerialPid();
virtual bool switchMode(USBDeviceConnected* pDev);
virtual USBEndpoint* getEp(USBDeviceConnected* pDev, int serialPortNumber, bool tx);
virtual int getSerialPortCount();
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 WAN_DONGLE_TYPE getType();
private:
bool m_hasSwitched;
int m_currentSerialIntf;
int m_endpointsToFetch;
};
class VodafoneK3772ZInitializer : public WANDongleInitializer
{
public:
VodafoneK3772ZInitializer(USBHost* pHost);
virtual uint16_t getMSDVid();
virtual uint16_t getMSDPid();
virtual uint16_t getSerialVid();
virtual uint16_t getSerialPid();
virtual bool switchMode(USBDeviceConnected* pDev);
virtual USBEndpoint* getEp(USBDeviceConnected* pDev, int serialPortNumber, bool tx);
virtual int getSerialPortCount();
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 WAN_DONGLE_TYPE getType();
private:
bool m_hasSwitched;
int m_currentSerialIntf;
int m_endpointsToFetch;
};
//-----------------------------------------------------------------------
// mamm, u-blox Modem
//-----------------------------------------------------------------------
class UbxInitializer : public WANDongleInitializer
{
public:
UbxInitializer(USBHost* pHost);
virtual uint16_t getMSDVid();
virtual uint16_t getMSDPid();
virtual uint16_t getSerialVid();
virtual uint16_t getSerialPid();
virtual bool switchMode(USBDeviceConnected* pDev);
virtual int getSerialPortCount();
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 WAN_DONGLE_TYPE getType();
private:
bool m_hasSwitched;
int m_currentSerialIntf;
int m_endpointsToFetch;
};
#endif /* USBHOST_3GMODULE */
#endif

View File

@ -0,0 +1,340 @@
/* Copyright (c) 2010-2012 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.
*/
#include "USBHostConf.h"
#ifdef USBHOST_3GMODULE
#define __DEBUG__ 0
#ifndef __MODULE__
#define __MODULE__ "WANDongleSerialPort.cpp"
#endif
#include "core/dbg.h"
#include <cstdint>
#include "rtos.h"
#include "WANDongleSerialPort.h"
WANDongleSerialPort::WANDongleSerialPort() : cb_tx_en(false), cb_rx_en(false), listener(NULL)
{
reset();
}
void WANDongleSerialPort::init(USBHost* pHost)
{
host = pHost;
}
void WANDongleSerialPort::reset()
{
tx_mtx.lock();
rx_mtx.lock();
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;
tx_mtx.unlock();
rx_mtx.unlock();
}
int WANDongleSerialPort::readPacket()
{
DBG("Read packet on %p", this);
rx_mtx.lock();
if(lock_rx)
{
ERR("Fail");
rx_mtx.unlock();
return -1;
}
if( bulk_in == NULL )
{
WARN("Port is disconnected");
rx_mtx.unlock();
return -1;
}
lock_rx = true; //Receiving
rx_mtx.unlock();
// DBG("readPacket");
//lock_rx.lock();
USB_TYPE res = host->bulkRead(dev, (USBEndpoint *)bulk_in, buf_in, ((USBEndpoint *)bulk_in)->getSize(), false); //Queue transfer
if(res != USB_TYPE_PROCESSING)
{
//lock_rx.unlock();
ERR("host->bulkRead() returned %d", res);
Thread::wait(100);
return -1;
}
return 0;
}
int WANDongleSerialPort::writePacket()
{
tx_mtx.lock();
if(lock_tx)
{
ERR("Fail");
tx_mtx.unlock();
return -1;
}
if( bulk_out == NULL )
{
WARN("Port is disconnected");
tx_mtx.unlock();
return -1;
}
lock_tx = true; //Transmitting
tx_mtx.unlock();
// DBG("writePacket");
//lock_tx.lock();
USB_TYPE res = host->bulkWrite(dev, (USBEndpoint *)bulk_out, buf_out, buf_out_len, false); //Queue transfer
if(res != USB_TYPE_PROCESSING)
{
//lock_tx.unlock();
ERR("host->bulkWrite() returned %d", res);
Thread::wait(100);
return -1;
}
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( USBDeviceConnected* pDev, USBEndpoint* pInEp, USBEndpoint* pOutEp )
{
dev = pDev;
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 (((USBEndpoint *) bulk_in)->getState() == USB_TYPE_IDLE) //Success
{
buf_in_read_pos = 0;
buf_in_len = ((USBEndpoint *) 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();
DBG("Trying again");
readPacket();
}
}
void WANDongleSerialPort::txHandler()
{
if (((USBEndpoint *) 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();
}
}
#endif /* USBHOST_3GMODULE */

View File

@ -0,0 +1,133 @@
/* Copyright (c) 2010-2012 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 "USBHostConf.h"
#ifdef USBHOST_3GMODULE
#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 WANDongleSerialPort : public IUSBHostSerial {
public:
/*
* Constructor
*
*/
WANDongleSerialPort();
void init( USBHost* pHost );
void connect( USBDeviceConnected* pDev, USBEndpoint* pInEp, USBEndpoint* 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:
USBEndpoint * bulk_in;
USBEndpoint * bulk_out;
USBHost * host;
USBDeviceConnected * dev;
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 /* USBHOST_3GMODULE */
#endif

View File

@ -21,47 +21,52 @@
* Maximum number of devices that can be connected
* to the usb host
*/
#define MAX_DEVICE_CONNECTED 5
#define MAX_DEVICE_CONNECTED 1
/*
* Maximum of Hub connected to the usb host
*/
#define MAX_HUB_NB 2
#define MAX_HUB_NB 0
/*
* Maximum number of ports on a USB hub
*/
#define MAX_HUB_PORT 4
#define MAX_HUB_PORT 0
/*
* Enable USBHostMSD
*/
#define USBHOST_MSD 1
#define USBHOST_MSD 0
/*
* Enable USBHostKeyboard
*/
#define USBHOST_KEYBOARD 1
#define USBHOST_KEYBOARD 0
/*
* Enable USBHostMouse
*/
#define USBHOST_MOUSE 1
#define USBHOST_MOUSE 0
/*
* Enable USBHostSerial
*/
#define USBHOST_SERIAL 1
#define USBHOST_SERIAL 0
/*
* Enable USB3Gmodule
*/
#define USBHOST_3GMODULE 1
/*
* Maximum number of interfaces of a usb device
*/
#define MAX_INTF 3
#define MAX_INTF 4
/*
* Maximum number of endpoints on each interface
*/
#define MAX_ENDPOINT_PER_INTERFACE 3
#define MAX_ENDPOINT_PER_INTERFACE 2
/*
* Maximum number of endpoint descriptors that can be allocated