pull/129/head
bcostm 2013-12-16 10:00:20 +01:00
commit b42dacb13d
19 changed files with 1378 additions and 175 deletions

View File

@ -49,7 +49,7 @@
#define USBHOST_MOUSE 1 #define USBHOST_MOUSE 1
/* /*
* Enable USBHostSerial * Enable USBHostSerial or USBHostMultiSerial (if set > 1)
*/ */
#define USBHOST_SERIAL 1 #define USBHOST_SERIAL 1

View File

@ -18,17 +18,35 @@
#define USB_DEBUG_H #define USB_DEBUG_H
//Debug is disabled by default //Debug is disabled by default
#define DEBUG 0 #define DEBUG 3 /*INFO,ERR,WARN*/
#define DEBUG_TRANSFER 0 #define DEBUG_TRANSFER 0
#define DEBUG_EP_STATE 0 #define DEBUG_EP_STATE 0
#define DEBUG_EVENT 0 #define DEBUG_EVENT 0
#if (DEBUG) #if (DEBUG > 3)
#define USB_DBG(x, ...) std::printf("[USB_DBG: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__); #define USB_DBG(x, ...) std::printf("[USB_DBG: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
#else #else
#define USB_DBG(x, ...) #define USB_DBG(x, ...)
#endif #endif
#if (DEBUG > 2)
#define USB_INFO(x, ...) std::printf("[USB_INFO: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
#else
#define USB_INFO(x, ...)
#endif
#if (DEBUG > 1)
#define USB_WARN(x, ...) std::printf("[USB_WARNING: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
#else
#define USB_WARN(x, ...)
#endif
#if (DEBUG > 0)
#define USB_ERR(x, ...) std::printf("[USB_ERR: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
#else
#define USB_ERR(x, ...)
#endif
#if (DEBUG_TRANSFER) #if (DEBUG_TRANSFER)
#define USB_DBG_TRANSFER(x, ...) std::printf("[USB_TRANSFER: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__); #define USB_DBG_TRANSFER(x, ...) std::printf("[USB_TRANSFER: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
#else #else
@ -41,9 +59,6 @@
#define USB_DBG_EVENT(x, ...) #define USB_DBG_EVENT(x, ...)
#endif #endif
#define USB_INFO(x, ...) std::printf("[USB_INFO: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
#define USB_WARN(x, ...) std::printf("[USB_WARNING: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
#define USB_ERR(x, ...) std::printf("[USB_ERR: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
#endif #endif

View File

@ -20,27 +20,17 @@
#include "dbg.h" #include "dbg.h"
#define SET_LINE_CODING 0x20 #define CHECK_INTERFACE(cls,subcls,proto) \
(((cls == 0xFF) && (subcls == 0xFF) && (proto == 0xFF)) /* QUALCOM CDC */ || \
((cls == SERIAL_CLASS) && (subcls == 0x00) && (proto == 0x00)) /* STANDARD CDC */ )
USBHostSerial::USBHostSerial(): circ_buf() { #if (USBHOST_SERIAL <= 1)
USBHostSerial::USBHostSerial()
{
host = USBHost::getHostInst(); host = USBHost::getHostInst();
size_bulk_in = 0; ports_found = 0;
size_bulk_out = 0;
init();
}
void USBHostSerial::init() {
dev = NULL;
bulk_in = NULL;
bulk_out = NULL;
dev_connected = false; dev_connected = false;
serial_intf = -1;
serial_device_found = false;
line_coding.baudrate = 9600;
line_coding.data_bits = 8;
line_coding.parity = None;
line_coding.stop_bits = 1;
circ_buf.flush();
} }
bool USBHostSerial::connected() bool USBHostSerial::connected()
@ -48,49 +38,219 @@ bool USBHostSerial::connected()
return dev_connected; return dev_connected;
} }
void USBHostSerial::disconnect(void)
{
ports_found = 0;
dev = NULL;
}
bool USBHostSerial::connect() { bool USBHostSerial::connect() {
if (dev_connected) { if (dev)
return true; {
for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++)
{
USBDeviceConnected* d = host->getDevice(i);
if (dev == d)
return true;
}
disconnect();
} }
for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) { for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++)
if ((dev = host->getDevice(i)) != NULL) { {
USBDeviceConnected* d = host->getDevice(i);
if (d != NULL) {
USB_DBG("Trying to connect serial device\r\n"); USB_DBG("Trying to connect serial device \r\n");
if(host->enumerate(d, this))
if(host->enumerate(dev, this))
break; break;
if (serial_device_found) { USBEndpoint* bulk_in = d->getEndpoint(port_intf, BULK_ENDPOINT, IN);
bulk_in = dev->getEndpoint(serial_intf, BULK_ENDPOINT, IN); USBEndpoint* bulk_out = d->getEndpoint(port_intf, BULK_ENDPOINT, OUT);
bulk_out = dev->getEndpoint(serial_intf, BULK_ENDPOINT, OUT); if (bulk_in && bulk_out)
{
if (!bulk_in || !bulk_out) USBHostSerialPort::connect(host,d,port_intf,bulk_in, bulk_out);
break; dev = d;
USB_INFO("New Serial device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, serial_intf);
dev->setName("Serial", serial_intf);
host->registerDriver(dev, serial_intf, this, &USBHostSerial::init);
baud(9600);
size_bulk_in = bulk_in->getSize();
size_bulk_out = bulk_out->getSize();
bulk_in->attach(this, &USBHostSerial::rxHandler);
bulk_out->attach(this, &USBHostSerial::txHandler);
host->bulkRead(dev, bulk_in, buf, size_bulk_in, false);
dev_connected = true;
return true;
} }
} }
} }
init(); return dev != NULL;
}
/*virtual*/ void USBHostSerial::setVidPid(uint16_t vid, uint16_t pid)
{
// we don't check VID/PID for MSD driver
}
/*virtual*/ bool USBHostSerial::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
{
if ((ports_found < USBHOST_MAXSERIAL) &&
CHECK_INTERFACE(intf_class, intf_subclass, intf_protocol)) {
port_intf = intf_nb;
ports_found = true;
return true;
}
return false; return false;
} }
void USBHostSerial::rxHandler() { /*virtual*/ bool USBHostSerial::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
{
if (ports_found && (intf_nb == port_intf)) {
if (type == BULK_ENDPOINT)
return true;
}
return false;
}
#else // (USBHOST_SERIAL > 1)
//------------------------------------------------------------------------------
USBHostMultiSerial::USBHostMultiSerial()
{
host = USBHost::getHostInst();
dev = NULL;
memset(ports, NULL, sizeof(ports));
ports_found = 0;
dev_connected = false;
}
USBHostMultiSerial::~USBHostMultiSerial()
{
disconnect();
}
bool USBHostMultiSerial::connected()
{
return dev_connected;
}
void USBHostMultiSerial::disconnect(void)
{
for (int port = 0; port < USBHOST_SERIAL; port ++)
{
if (ports[port])
{
delete ports[port];
ports[port] = NULL;
}
}
ports_found = 0;
dev = NULL;
}
bool USBHostMultiSerial::connect() {
if (dev)
{
for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++)
{
USBDeviceConnected* d = host->getDevice(i);
if (dev == d)
return true;
}
disconnect();
}
for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++)
{
USBDeviceConnected* d = host->getDevice(i);
if (d != NULL) {
USB_DBG("Trying to connect serial device \r\n");
if(host->enumerate(d, this))
break;
for (int port = 0; port < ports_found; port ++)
{
USBEndpoint* bulk_in = d->getEndpoint(port_intf[port], BULK_ENDPOINT, IN);
USBEndpoint* bulk_out = d->getEndpoint(port_intf[port], BULK_ENDPOINT, OUT);
if (bulk_in && bulk_out)
{
ports[port] = new USBHostSerialPort();
if (ports[port])
{
ports[port]->connect(host,d,port_intf[port],bulk_in, bulk_out);
dev = d;
}
}
}
}
}
return dev != NULL;
}
/*virtual*/ void USBHostMultiSerial::setVidPid(uint16_t vid, uint16_t pid)
{
// we don't check VID/PID for MSD driver
}
/*virtual*/ bool USBHostMultiSerial::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
{
if ((ports_found < USBHOST_SERIAL) &&
CHECK_INTERFACE(intf_class, intf_subclass, intf_protocol)) {
port_intf[ports_found++] = intf_nb;
return true;
}
return false;
}
/*virtual*/ bool USBHostMultiSerial::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
{
if ((ports_found > 0) && (intf_nb == port_intf[ports_found-1])) {
if (type == BULK_ENDPOINT)
return true;
}
return false;
}
#endif
//------------------------------------------------------------------------------
#define SET_LINE_CODING 0x20
USBHostSerialPort::USBHostSerialPort(): circ_buf()
{
init();
}
void USBHostSerialPort::init(void)
{
host = NULL;
dev = NULL;
serial_intf = NULL;
size_bulk_in = 0;
size_bulk_out = 0;
bulk_in = NULL;
bulk_out = NULL;
line_coding.baudrate = 9600;
line_coding.data_bits = 8;
line_coding.parity = None;
line_coding.stop_bits = 1;
circ_buf.flush();
}
void USBHostSerialPort::connect(USBHost* _host, USBDeviceConnected * _dev,
uint8_t _serial_intf, USBEndpoint* _bulk_in, USBEndpoint* _bulk_out)
{
host = _host;
dev = _dev;
serial_intf = _serial_intf;
bulk_in = _bulk_in;
bulk_out = _bulk_out;
USB_INFO("New Serial device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, serial_intf);
dev->setName("Serial", serial_intf);
host->registerDriver(dev, serial_intf, this, &USBHostSerialPort::init);
//baud(9600);
size_bulk_in = bulk_in->getSize();
size_bulk_out = bulk_out->getSize();
bulk_in->attach(this, &USBHostSerialPort::rxHandler);
bulk_out->attach(this, &USBHostSerialPort::txHandler);
host->bulkRead(dev, bulk_in, buf, size_bulk_in, false);
}
void USBHostSerialPort::rxHandler() {
if (bulk_in) { if (bulk_in) {
int len = bulk_in->getLengthTransferred(); int len = bulk_in->getLengthTransferred();
if (bulk_in->getState() == USB_TYPE_IDLE) { if (bulk_in->getState() == USB_TYPE_IDLE) {
@ -103,7 +263,7 @@ void USBHostSerial::rxHandler() {
} }
} }
void USBHostSerial::txHandler() { void USBHostSerialPort::txHandler() {
if (bulk_out) { if (bulk_out) {
if (bulk_out->getState() == USB_TYPE_IDLE) { if (bulk_out->getState() == USB_TYPE_IDLE) {
tx.call(); tx.call();
@ -111,7 +271,7 @@ void USBHostSerial::txHandler() {
} }
} }
int USBHostSerial::_putc(int c) { int USBHostSerialPort::_putc(int c) {
if (bulk_out) { if (bulk_out) {
if (host->bulkWrite(dev, bulk_out, (uint8_t *)&c, 1) == USB_TYPE_OK) { if (host->bulkWrite(dev, bulk_out, (uint8_t *)&c, 1) == USB_TYPE_OK) {
return 1; return 1;
@ -120,12 +280,12 @@ int USBHostSerial::_putc(int c) {
return -1; return -1;
} }
void USBHostSerial::baud(int baudrate) { void USBHostSerialPort::baud(int baudrate) {
line_coding.baudrate = baudrate; line_coding.baudrate = baudrate;
format(line_coding.data_bits, (Parity)line_coding.parity, line_coding.stop_bits); format(line_coding.data_bits, (Parity)line_coding.parity, line_coding.stop_bits);
} }
void USBHostSerial::format(int bits, Parity parity, int stop_bits) { void USBHostSerialPort::format(int bits, Parity parity, int stop_bits) {
line_coding.data_bits = bits; line_coding.data_bits = bits;
line_coding.parity = parity; line_coding.parity = parity;
line_coding.stop_bits = (stop_bits == 1) ? 0 : 2; line_coding.stop_bits = (stop_bits == 1) ? 0 : 2;
@ -137,7 +297,7 @@ void USBHostSerial::format(int bits, Parity parity, int stop_bits) {
0, serial_intf, (uint8_t *)&line_coding, 7); 0, serial_intf, (uint8_t *)&line_coding, 7);
} }
int USBHostSerial::_getc() { int USBHostSerialPort::_getc() {
uint8_t c = 0; uint8_t c = 0;
if (bulk_in == NULL) { if (bulk_in == NULL) {
init(); init();
@ -148,37 +308,36 @@ int USBHostSerial::_getc() {
return c; return c;
} }
int USBHostSerialPort::writeBuf(const char* b, int s)
{
int c = 0;
if (bulk_out)
{
while (c < s)
{
int i = (s < size_bulk_out) ? s : size_bulk_out;
if (host->bulkWrite(dev, bulk_out, (uint8_t *)(b+c), i) == USB_TYPE_OK)
c += i;
}
}
return s;
}
uint8_t USBHostSerial::available() { int USBHostSerialPort::readBuf(char* b, int s)
{
int i = 0;
if (bulk_in)
{
for (i = 0; i < s; )
b[i++] = getc();
}
return i;
}
uint8_t USBHostSerialPort::available() {
return circ_buf.available(); return circ_buf.available();
} }
/*virtual*/ void USBHostSerial::setVidPid(uint16_t vid, uint16_t pid)
{
// we don't check VID/PID for MSD driver
}
/*virtual*/ bool USBHostSerial::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
{
if ((serial_intf == -1) &&
(intf_class == SERIAL_CLASS) &&
(intf_subclass == 0x00) &&
(intf_protocol == 0x00)) {
serial_intf = intf_nb;
return true;
}
return false;
}
/*virtual*/ bool USBHostSerial::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
{
if (intf_nb == serial_intf) {
if (type == BULK_ENDPOINT) {
serial_device_found = true;
return true;
}
}
return false;
}
#endif #endif

View File

@ -28,12 +28,12 @@
/** /**
* A class to communicate a USB virtual serial port * A class to communicate a USB virtual serial port
*/ */
class USBHostSerial : public IUSBEnumerator, public Stream { class USBHostSerialPort : public Stream {
public: public:
/** /**
* Constructor * Constructor
*/ */
USBHostSerial(); USBHostSerialPort();
enum IrqType { enum IrqType {
RxIrq, RxIrq,
@ -48,20 +48,9 @@ public:
Space Space
}; };
/** void connect(USBHost* _host, USBDeviceConnected * _dev,
* Check if a virtual serial port is connected uint8_t _serial_intf, USBEndpoint* _bulk_in, USBEndpoint* _bulk_out);
*
* @returns true if a serial device is connected
*/
bool connected();
/**
* Try to connect a serial device
*
* @return true if connection was successful
*/
bool connect();
/** /**
* Check the number of bytes available. * Check the number of bytes available.
* *
@ -111,34 +100,29 @@ public:
/** Set the transmission format used by the Serial port /** Set the transmission format used by the Serial port
* *
* @param bits The number of bits in a word (default = 8) * @param bits The number of bits in a word (default = 8)
* @param parity The parity used (USBHostSerial::None, USBHostSerial::Odd, USBHostSerial::Even, USBHostSerial::Mark, USBHostSerial::Space; default = USBHostSerial::None) * @param parity The parity used (USBHostSerialPort::None, USBHostSerialPort::Odd, USBHostSerialPort::Even, USBHostSerialPort::Mark, USBHostSerialPort::Space; default = USBHostSerialPort::None)
* @param stop The number of stop bits (1 or 2; default = 1) * @param stop The number of stop bits (1 or 2; default = 1)
*/ */
void format(int bits = 8, Parity parity = USBHostSerial::None, int stop_bits = 1); void format(int bits = 8, Parity parity = USBHostSerialPort::None, int stop_bits = 1);
virtual int writeBuf(const char* b, int s);
virtual int readBuf(char* b, int s);
protected: protected:
//From IUSBEnumerator
virtual void setVidPid(uint16_t vid, uint16_t pid);
virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
virtual int _getc(); virtual int _getc();
virtual int _putc(int c); virtual int _putc(int c);
private: private:
USBHost * host; USBHost * host;
USBDeviceConnected * dev; USBDeviceConnected * dev;
USBEndpoint * bulk_in; USBEndpoint * bulk_in;
USBEndpoint * bulk_out; USBEndpoint * bulk_out;
uint32_t size_bulk_in; uint32_t size_bulk_in;
uint32_t size_bulk_out; uint32_t size_bulk_out;
bool dev_connected;
void init(); void init();
MtxCircBuffer<uint8_t, 64> circ_buf; MtxCircBuffer<uint8_t, 128> circ_buf;
uint8_t buf[64]; uint8_t buf[64];
@ -156,11 +140,92 @@ private:
FunctionPointer rx; FunctionPointer rx;
FunctionPointer tx; FunctionPointer tx;
int serial_intf; uint8_t serial_intf;
bool serial_device_found;
}; };
#if (USBHOST_SERIAL <= 1)
class USBHostSerial : public IUSBEnumerator, public USBHostSerialPort
{
public:
USBHostSerial();
/**
* Try to connect a serial device
*
* @return true if connection was successful
*/
bool connect();
void disconnect();
/**
* Check if a any serial port is connected
*
* @returns true if a serial device is connected
*/
bool connected();
protected:
USBHost* host;
USBDeviceConnected* dev;
uint8_t port_intf;
int ports_found;
//From IUSBEnumerator
virtual void setVidPid(uint16_t vid, uint16_t pid);
virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
private:
bool dev_connected;
};
#else // (USBHOST_SERIAL > 1)
class USBHostMultiSerial : public IUSBEnumerator {
public:
USBHostMultiSerial();
virtual ~USBHostMultiSerial();
USBHostSerialPort* getPort(int port)
{
return port < USBHOST_SERIAL ? ports[port] : NULL;
}
/**
* Try to connect a serial device
*
* @return true if connection was successful
*/
bool connect();
void disconnect();
/**
* Check if a any serial port is connected
*
* @returns true if a serial device is connected
*/
bool connected();
protected:
USBHost* host;
USBDeviceConnected* dev;
USBHostSerialPort* ports[USBHOST_SERIAL];
uint8_t port_intf[USBHOST_SERIAL];
int ports_found;
//From IUSBEnumerator
virtual void setVidPid(uint16_t vid, uint16_t pid);
virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
private:
bool dev_connected;
};
#endif // (USBHOST_SERIAL <= 1)
#endif #endif
#endif #endif

View File

@ -63,30 +63,33 @@ int ATCommandsInterface::open()
} }
//Initialize AT link & start events processing //Initialize AT link & start events processing
int ATCommandsInterface::init() int ATCommandsInterface::init(bool reset /* = true*/)
{ {
DBG("Sending ATZ E1 V1");
//Lock transaction mutex //Lock transaction mutex
m_transactionMtx.lock(); m_transactionMtx.lock();
//Should we flush m_pStream at this point ??? if (reset)
int err;
int tries = 5;
do
{ {
err = executeInternal("ATZ E1 V1", this, NULL, 3000); //Enable echo and verbosity DBG("Sending ATZ E1 V1");
if(err && tries) //Should we flush m_pStream at this point ???
int err;
int tries = 5;
do
{ {
WARN("No response, trying again"); err = executeInternal("ATZ E1 V1", this, NULL, 3000); //Enable echo and verbosity
Thread::wait(1000); //Give dongle time to recover if(err && tries)
{
WARN("No response, trying again");
Thread::wait(1000); //Give dongle time to recover
}
} while(err && tries--);
if( err )
{
ERR("Sending ATZ E1 V1 returned with err code %d", err);
m_transactionMtx.unlock();
return err;
} }
} while(err && tries--);
if( err )
{
ERR("Sending ATZ E1 V1 returned with err code %d", err);
m_transactionMtx.unlock();
return err;
} }
//Enable events handling and execute events enabling commands //Enable events handling and execute events enabling commands

View File

@ -77,7 +77,7 @@ public:
int open(); int open();
//Initialize AT link //Initialize AT link
int init(); int init(bool reset = true);
//Close connection //Close connection
int close(); int close();

View File

@ -50,22 +50,15 @@ extern "C" {
#include "netif/ppp/ppp.h" #include "netif/ppp/ppp.h"
} }
PPPIPInterface::PPPIPInterface(IOStream* pStream, const char* msisdn) : LwIPInterface(), m_linkStatusSphre(1), m_pppErrCode(0), m_pStream(pStream), m_streamAvail(true), m_pppd(-1) PPPIPInterface::PPPIPInterface(IOStream* pStream) : LwIPInterface(), m_linkStatusSphre(1), m_pppErrCode(0), m_pStream(pStream), m_streamAvail(true), m_pppd(-1)
{ {
m_connectCmd = new char[strlen(CONNECT_CMD_PREFIX) + strlen(msisdn) + strlen(CONNECT_CMD_SUFFIX) + 1];
sprintf(m_connectCmd, "%s%s%s", CONNECT_CMD_PREFIX, msisdn, CONNECT_CMD_SUFFIX);
m_expectedResp = new char[strlen(m_connectCmd) + strlen(EXPECTED_RESP_SUFFIX) + 1];
sprintf(m_expectedResp, "%s%s", m_connectCmd, EXPECTED_RESP_SUFFIX);
m_expectedRespDatarate = new char[strlen(m_connectCmd) + strlen(EXPECTED_RESP_DATARATE_SUFFIX) + 1];
sprintf(m_expectedRespDatarate, "%s%s", m_connectCmd, EXPECTED_RESP_DATARATE_SUFFIX);
m_linkStatusSphre.wait(); m_linkStatusSphre.wait();
} }
/*virtual*/ PPPIPInterface::~PPPIPInterface() /*virtual*/ PPPIPInterface::~PPPIPInterface()
{ {
delete m_connectCmd;
delete m_expectedResp;
delete m_expectedRespDatarate;
} }
/*virtual*/ int PPPIPInterface::init() //Init PPP-specific stuff, create the right bindings, etc /*virtual*/ int PPPIPInterface::init() //Init PPP-specific stuff, create the right bindings, etc
@ -78,10 +71,11 @@ PPPIPInterface::PPPIPInterface(IOStream* pStream, const char* msisdn) : LwIPInte
return OK; return OK;
} }
int PPPIPInterface::setup(const char* user, const char* pw) int PPPIPInterface::setup(const char* user, const char* pw, const char* msisdn)
{ {
DBG("Configuring PPP authentication method"); DBG("Configuring PPP authentication method");
pppSetAuth(PPPAUTHTYPE_ANY, user, pw); pppSetAuth(PPPAUTHTYPE_ANY, user, pw);
m_msisdn = msisdn;
DBG("Done"); DBG("Done");
return OK; return OK;
} }
@ -89,22 +83,22 @@ int PPPIPInterface::setup(const char* user, const char* pw)
/*virtual*/ int PPPIPInterface::connect() /*virtual*/ int PPPIPInterface::connect()
{ {
int ret; int ret;
char cmd[32];
int cmdLen;
char buf[32]; char buf[32];
size_t len; size_t len;
DBG("Trying to connect with PPP"); DBG("Trying to connect with PPP");
cleanupLink(); cleanupLink();
DBG("Sending %s", m_connectCmd); cmdLen = sprintf(cmd, "%s%s%s", CONNECT_CMD_PREFIX, m_msisdn, CONNECT_CMD_SUFFIX);
DBG("Sending %s", cmd);
ret = m_pStream->write((uint8_t*)m_connectCmd, strlen(m_connectCmd), osWaitForever); ret = m_pStream->write((uint8_t*)cmd, cmdLen, osWaitForever);
if( ret != OK ) if( ret != OK )
{ {
return NET_UNKNOWN; return NET_UNKNOWN;
} }
DBG("Expect %s", m_expectedResp);
len = 0; len = 0;
size_t readLen; size_t readLen;
ret = m_pStream->read((uint8_t*)buf + len, &readLen, EXPECTED_RESP_MIN_LEN, 10000); ret = m_pStream->read((uint8_t*)buf + len, &readLen, EXPECTED_RESP_MIN_LEN, 10000);
@ -128,16 +122,21 @@ int PPPIPInterface::setup(const char* user, const char* pw)
DBG("Got %s[len %d]", buf, len); DBG("Got %s[len %d]", buf, len);
int datarate = 0; int datarate = 0;
if( (sscanf(buf, m_expectedRespDatarate, &datarate ) != 1) && (strcmp(m_expectedResp, buf) != 0) ) strcpy(&cmd[cmdLen], EXPECTED_RESP_DATARATE_SUFFIX);
if( (sscanf(buf, cmd, &datarate ) != 1))
{ {
//Discard buffer strcpy(&cmd[cmdLen], EXPECTED_RESP_SUFFIX);
do //Clear buf if (strcmp(cmd, buf) != 0)
{ {
ret = m_pStream->read((uint8_t*)buf, &len, 32, 0); //Discard buffer
} while( (ret == OK) && (len > 0) ); do //Clear buf
return NET_CONN; {
} ret = m_pStream->read((uint8_t*)buf, &len, 32, 0);
} while( (ret == OK) && (len > 0) );
return NET_CONN;
}
}
DBG("Transport link open"); DBG("Transport link open");
if(datarate != 0) if(datarate != 0)
{ {

View File

@ -40,11 +40,11 @@ using namespace rtos;
class PPPIPInterface : public LwIPInterface class PPPIPInterface : public LwIPInterface
{ {
public: public:
PPPIPInterface(IOStream* pStream, const char* msisdn); PPPIPInterface(IOStream* pStream);
virtual ~PPPIPInterface(); virtual ~PPPIPInterface();
int init(); //Init PPP-specific stuff, create the right bindings, etc int init(); //Init PPP-specific stuff, create the right bindings, etc
int setup(const char* user, const char* pw); //Setup authentication int setup(const char* user, const char* pw, const char* msisdn); //Setup authentication
virtual int connect(); virtual int connect();
virtual int disconnect(); virtual int disconnect();
@ -57,16 +57,13 @@ private:
IOStream* m_pStream; //Serial stream IOStream* m_pStream; //Serial stream
bool m_streamAvail; bool m_streamAvail;
const char* m_msisdn;
int m_pppd; int m_pppd;
friend u32_t sio_write(sio_fd_t fd, u8_t *data, u32_t len); friend u32_t sio_write(sio_fd_t fd, u8_t *data, u32_t len);
friend u32_t sio_read(sio_fd_t fd, u8_t *data, u32_t len); friend u32_t sio_read(sio_fd_t fd, u8_t *data, u32_t len);
friend void sio_read_abort(sio_fd_t fd); friend void sio_read_abort(sio_fd_t fd);
char* m_connectCmd;
char* m_expectedResp;
char* m_expectedRespDatarate;
}; };
#endif /* PPPIPINTERFACE_H_ */ #endif /* PPPIPINTERFACE_H_ */

View File

@ -0,0 +1,253 @@
/* IOSerialStream.cpp */
/* Copyright (C) 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.
*/
#define __DEBUG__ 0 //Maximum verbosity
#ifndef __MODULE__
#define __MODULE__ "IOSerialStream.cpp"
#endif
#include "core/fwk.h"
#include <cstring>
#include "IOSerialStream.h"
#define UART_X ((LPC_UART_TypeDef *)(UART_1))
IOSerialStream::IOSerialStream(mbed::RawSerial& serial) : m_serial(serial), m_serialTxFifoEmpty(true),
m_availableSphre(1), m_spaceSphre(1), m_inBuf(), m_outBuf()
{
m_availableSphre.wait();
m_spaceSphre.wait();
//Attach interrupts
m_serial.attach(this, &IOSerialStream::readable, mbed::SerialBase::RxIrq);
m_serial.attach(this, &IOSerialStream::writeable, mbed::SerialBase::TxIrq);
}
/*virtual*/ IOSerialStream::~IOSerialStream()
{
m_serial.attach(NULL, mbed::SerialBase::RxIrq);
m_serial.attach(NULL, mbed::SerialBase::TxIrq);
}
//0 for non-blocking (returns immediately), osWaitForever for infinite blocking
/*virtual*/ int IOSerialStream::read(uint8_t* buf, size_t* pLength, size_t maxLength, uint32_t timeout/*=osWaitForever*/)
{
DBG("Trying to read at most %d chars", maxLength);
int ret = waitAvailable(timeout);
if(ret)
{
WARN("Error %d while waiting for incoming data", ret);
return ret;
}
int readLen = MIN( available(), maxLength );
*pLength = readLen;
setupReadableISR(false);
while(readLen--)
{
m_inBuf.dequeue(buf);
buf++;
}
setupReadableISR(true);
DBG("Read %d chars successfully", *pLength);
return OK;
}
/*virtual*/ size_t IOSerialStream::available()
{
setupReadableISR(false); //m_inBuf.available() is not reentrant
size_t len = m_inBuf.available();
setupReadableISR(true);
return len;
}
/*virtual*/ int IOSerialStream::waitAvailable(uint32_t timeout/*=osWaitForever*/) //Wait for data to be available
{
int ret;
if(available()) //Is data already available?
{
m_availableSphre.wait(0); //Clear the queue as data is available
return OK;
}
DBG("Waiting for data availability %d ms (-1 is infinite)", timeout);
ret = m_availableSphre.wait(timeout); //Wait for data to arrive or for abort
if(ret <= 0)
{
DBG("Timeout");
return NET_TIMEOUT;
}
if(!available()) //Even if abort has been called, return that data is available
{
DBG("Aborted");
return NET_INTERRUPTED;
}
DBG("Finished waiting");
m_availableSphre.wait(0); //Clear the queue as data is available
return OK;
}
/*virtual*/ int IOSerialStream::abortRead() //Abort current reading (or waiting) operation
{
if( !available() ) //If there is data pending, no need to abort
{
m_availableSphre.release(); //Force exiting the waiting state; kludge to pass a RC directly
}
else
{
DBG("Serial is readable"); ;
}
return OK;
}
void IOSerialStream::setupReadableISR(bool en)
{
if(en)
{
UART_X->IER |= 1 << 0;
}
else
{
UART_X->IER &= ~(1 << 0);
}
}
void IOSerialStream::readable() //Callback from m_serial when new data is available
{
do
{
m_inBuf.queue(m_serial.getc());
} while(m_serial.readable());
m_availableSphre.release(); //Force exiting the waiting state
}
//0 for non-blocking (returns immediately), osWaitForever for infinite blocking
/*virtual*/ int IOSerialStream::write(uint8_t* buf, size_t length, uint32_t timeout/*=osWaitForever*/)
{
DBG("Trying to write %d chars", length);
int ret = waitSpace(timeout);
if(ret)
{
WARN("Error %d while waiting for space", ret);
return ret;
}
DBG("Writing %d chars", length);
setupWriteableISR(false);
while(length)
{
m_outBuf.queue(*buf);
buf++;
length--;
if(length && !space())
{
DBG("Waiting to write remaining %d chars", length);
setupWriteableISR(true);
ret = waitSpace(timeout);
if(ret)
{
WARN("Error %d while waiting for space", ret);
return ret;
}
setupWriteableISR(false);
}
}
//If m_serial tx fifo is empty we need to manually tx a byte in order to trigger the interrupt
if( m_outBuf.available() && m_serialTxFifoEmpty )
{
m_serialTxFifoEmpty = false;
uint8_t c;
m_outBuf.dequeue(&c);
m_serial.putc((char)c);
}
setupWriteableISR(true);
DBG("Write successful");
return OK;
}
/*virtual*/ size_t IOSerialStream::space()
{
setupWriteableISR(false); //m_outBuf.available() is not reentrant
size_t len = CIRCBUF_SIZE - m_outBuf.available();
setupWriteableISR(true);
return len;
}
/*virtual*/ int IOSerialStream::waitSpace(uint32_t timeout/*=osWaitForever*/) //Wait for space to be available
{
int ret;
if(space()) //Is still space already left?
{
m_spaceSphre.wait(0); //Clear the queue as space is available
return OK;
}
DBG("Waiting for data space %d ms (-1 is infinite)", timeout);
ret = m_spaceSphre.wait(timeout); //Wait for space to be made or for abort
if(ret <= 0)
{
DBG("Timeout");
return NET_TIMEOUT;
}
if(!space()) //Even if abort has been called, return that space is available
{
DBG("Aborted");
return NET_INTERRUPTED;
}
m_spaceSphre.wait(0); //Clear the queue as space is available
return OK;
}
/*virtual*/ int IOSerialStream::abortWrite() //Abort current writing (or waiting) operation
{
if( !space() ) //If there is space left, no need to abort
{
m_spaceSphre.release(); //Force exiting the waiting state
}
return OK;
}
void IOSerialStream::setupWriteableISR(bool en)
{
if(en)
{
UART_X->IER |= 1 << 1;
}
else
{
UART_X->IER &= ~(1 << 1);
}
}
void IOSerialStream::writeable() //Callback from m_serial when new space is available
{
if(m_outBuf.isEmpty())
{
m_serialTxFifoEmpty = true;
}
else
{
while(m_serial.writeable() && !m_outBuf.isEmpty())
{
uint8_t c;
m_outBuf.dequeue(&c);
m_serial.putc((char)c);
}
}
m_spaceSphre.release(); //Force exiting the waiting state
}

View File

@ -0,0 +1,72 @@
/* IOSerialStream.h */
/* Copyright (C) 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 IOSERIALSTREAM_H_
#define IOSERIALSTREAM_H_
#include "core/fwk.h"
#include "RawSerial.h"
#include "rtos.h"
#include "core/MtxCircBuffer.h"
/** Input Serial Stream for physical serial interfaces (UART...)
This class is not thread-safe, except for the *Abort() methods that can be called by any thread/ISR
*/
class IOSerialStream : public IOStream
{
public:
enum { CIRCBUF_SIZE = 255 };
IOSerialStream(mbed::RawSerial& serial);
/*virtual*/ ~IOSerialStream();
//0 for non-blocking (returns immediately), osWaitForever for infinite blocking
virtual int read(uint8_t* buf, size_t* pLength, size_t maxLength, uint32_t timeout=osWaitForever);
virtual size_t available();
virtual int waitAvailable(uint32_t timeout=osWaitForever); //Wait for data to be available
virtual int abortRead(); //Abort current reading (or waiting) operation
//0 for non-blocking (returns immediately), osWaitForever for infinite blocking
virtual int write(uint8_t* buf, size_t length, uint32_t timeout=osWaitForever);
virtual size_t space();
virtual int waitSpace(uint32_t timeout=osWaitForever); //Wait for space to be available
virtual int abortWrite(); //Abort current writing (or waiting) operation
private:
mbed::RawSerial& m_serial;
volatile bool m_serialTxFifoEmpty;
void setupReadableISR(bool en);
void readable(); //Callback from m_serial when new data is available
Semaphore m_availableSphre; //Used for signalling
void setupWriteableISR(bool en);
void writeable(); //Callback from m_serial when new space is available
Semaphore m_spaceSphre; //Used for signalling
MtxCircBuffer<uint8_t, CIRCBUF_SIZE + 1> m_inBuf;
MtxCircBuffer<uint8_t, CIRCBUF_SIZE + 1> m_outBuf;
};
#endif /* IOSERIALSTREAM_H_ */

View File

@ -32,10 +32,11 @@
/* Input Serial Stream for USB virtual serial ports interfaces /* Input Serial Stream for USB virtual serial ports interfaces
This class is not thread-safe, except for the *Abort() methods that can be called by any thread/ISR This class is not thread-safe, except for the *Abort() methods that can be called by any thread/ISR
*/ */
#define CIRCBUF_SIZE 127
class USBSerialStream : public IOStream, IUSBHostSerialListener class USBSerialStream : public IOStream, IUSBHostSerialListener
{ {
public: public:
enum { CIRCBUF_SIZE = 127 };
USBSerialStream(IUSBHostSerial& serial); USBSerialStream(IUSBHostSerial& serial);
/*virtual*/ ~USBSerialStream(); /*virtual*/ ~USBSerialStream();

View File

@ -109,6 +109,6 @@ int UbloxCDMAModemInitializer::getSerialPortCount()
/*virtual*/ int UbloxCDMAModemInitializer::getType() /*virtual*/ int UbloxCDMAModemInitializer::getType()
{ {
return WAN_DONGLE_TYPE_UBLOXC200; return WAN_DONGLE_TYPE_UBLOX_LISAC200;
} }

View File

@ -27,7 +27,7 @@
enum enum
{ {
WAN_DONGLE_TYPE_UBLOXC200 WAN_DONGLE_TYPE_UBLOX_LISAC200 = 0xC200,
}; };
class UbloxCDMAModemInitializer : public WANDongleInitializer class UbloxCDMAModemInitializer : public WANDongleInitializer

View File

@ -126,6 +126,6 @@ int UbloxGSMModemInitializer::getSerialPortCount()
/*virtual*/ int UbloxGSMModemInitializer::getType() /*virtual*/ int UbloxGSMModemInitializer::getType()
{ {
return WAN_DONGLE_TYPE_UBX; return WAN_DONGLE_TYPE_UBLOX_LISAU200;
} }

View File

@ -23,7 +23,7 @@
enum enum
{ {
WAN_DONGLE_TYPE_UBX WAN_DONGLE_TYPE_UBLOX_LISAU200 = 0x0200
}; };
//----------------------------------------------------------------------- //-----------------------------------------------------------------------

View File

@ -0,0 +1,471 @@
/* UbloxModem.cpp */
/* Copyright (C) 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.
*/
#define __DEBUG__ 3
#ifndef __MODULE__
#define __MODULE__ "UbloxModem.cpp"
#endif
#include "core/fwk.h"
#include "sms/GSMSMSInterface.h"
#include "sms/CDMASMSInterface.h"
#include "UbloxModem.h"
UbloxModem::UbloxModem(IOStream* atStream, IOStream* pppStream) :
m_at(atStream), // Construct ATCommandsInterface with the AT serial channel
m_CdmaSms(&m_at), // Construct SMSInterface with the ATCommandsInterface
m_GsmSms(&m_at), // Construct SMSInterface with the ATCommandsInterface
m_ussd(&m_at), // Construct USSDInterface with the ATCommandsInterface
m_linkMonitor(&m_at), // Construct LinkMonitor with the ATCommandsInterface
m_ppp(pppStream ? pppStream : atStream), // Construct PPPIPInterface with the PPP serial channel
m_ipInit(false), // PPIPInterface connection is initially down
m_smsInit(false), // SMSInterface starts un-initialised
m_ussdInit(false), // USSDInterface starts un-initialised
m_linkMonitorInit(false), // LinkMonitor subsystem starts un-initialised
m_atOpen(false), // ATCommandsInterface starts in a closed state
m_onePort(pppStream == NULL),
m_gsm(true)
{
}
class CREGProcessor : public IATCommandsProcessor
{
public:
CREGProcessor(bool gsm) : status(STATUS_REGISTERING)
{
m_gsm = gsm;
}
enum REGISTERING_STATUS { STATUS_REGISTERING, STATUS_OK, STATUS_FAILED };
REGISTERING_STATUS getStatus()
{
return status;
}
const char* getAtCommand()
{
return m_gsm ? "AT+CREG?" : "AT+CSS?";
}
private:
virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
{
int r;
if (m_gsm)
{
if( sscanf(line, "+CREG: %*d,%d", &r) == 1 )
{
status = (r == 1 || r == 5) ? STATUS_OK :
(r == 0 || r == 2) ? STATUS_REGISTERING :
// (r == 3) ? STATUS_FAILED :
STATUS_FAILED;
}
}
else
{
char bc[3] = "";
if(sscanf(line, "%*s %*c,%2s,%*d",bc)==1)
{
status = (strcmp("Z", bc) == 0) ? STATUS_REGISTERING : STATUS_OK;
}
}
return OK;
}
virtual int onNewEntryPrompt(ATCommandsInterface* pInst)
{
return OK;
}
volatile REGISTERING_STATUS status;
bool m_gsm;
};
int UbloxModem::connect(const char* apn, const char* user, const char* password)
{
if( !m_ipInit )
{
m_ipInit = true;
m_ppp.init();
}
m_ppp.setup(user, password, m_gsm ? DEFAULT_MSISDN_GSM : DEFAULT_MSISDN_CDMA);
int ret = init();
if(ret)
{
return ret;
}
if (m_onePort)
{
m_smsInit = false; //SMS status reset
m_ussdInit = false; //USSD status reset
m_linkMonitorInit = false; //Link monitor status reset
}
ATCommandsInterface::ATResult result;
if(apn != NULL)
{
char cmd[48];
int tries = 30;
sprintf(cmd, "AT+CGDCONT=1,\"IP\",\"%s\"", apn);
do //Try 30 times because for some reasons it can fail *a lot* with the K3772-Z dongle
{
ret = m_at.executeSimple(cmd, &result);
DBG("Result of command: Err code=%d", ret);
if(ret)
{
Thread::wait(500);
}
} while(ret && --tries);
DBG("ATResult: AT return=%d (code %d)", result.result, result.code);
DBG("APN set to %s", apn);
}
//Connect
DBG("Connecting");
if (m_onePort)
{
m_at.close(); // Closing AT parser
m_atOpen = false; //Will need to be reinitialized afterwards
}
DBG("Connecting PPP");
ret = m_ppp.connect();
DBG("Result of connect: Err code=%d", ret);
return ret;
}
int UbloxModem::disconnect()
{
DBG("Disconnecting from PPP");
int ret = m_ppp.disconnect();
if(ret)
{
ERR("Disconnect returned %d, still trying to disconnect", ret);
}
//Ugly but leave dongle time to recover
Thread::wait(500);
if (m_onePort)
{
//ATCommandsInterface::ATResult result;
DBG("Starting AT thread");
ret = m_at.open();
if(ret)
{
return ret;
}
}
DBG("Trying to hangup");
if (m_onePort)
{
//Reinit AT parser
ret = m_at.init(false);
DBG("Result of command: Err code=%d\n", ret);
if(ret)
{
m_at.close(); // Closing AT parser
DBG("AT Parser closed, could not complete disconnection");
return NET_TIMEOUT;
}
}
return OK;
}
int UbloxModem::sendSM(const char* number, const char* message)
{
int ret = init();
if(ret)
{
return ret;
}
ISMSInterface* sms;
if (m_gsm) sms = &m_GsmSms;
else sms = &m_CdmaSms;
if(!m_smsInit)
{
ret = sms->init();
if(ret)
{
return ret;
}
m_smsInit = true;
}
ret = sms->send(number, message);
if(ret)
{
return ret;
}
return OK;
}
int UbloxModem::getSM(char* number, char* message, size_t maxLength)
{
int ret = init();
if(ret)
{
return ret;
}
ISMSInterface* sms;
if (m_gsm) sms = &m_GsmSms;
else sms = &m_CdmaSms;
if(!m_smsInit)
{
ret = sms->init();
if(ret)
{
return ret;
}
m_smsInit = true;
}
ret = sms->get(number, message, maxLength);
if(ret)
{
return ret;
}
return OK;
}
int UbloxModem::getSMCount(size_t* pCount)
{
int ret = init();
if(ret)
{
return ret;
}
ISMSInterface* sms;
if (m_gsm) sms = &m_GsmSms;
else sms = &m_CdmaSms;
if(!m_smsInit)
{
ret = sms->init();
if(ret)
{
return ret;
}
m_smsInit = true;
}
ret = sms->getCount(pCount);
if(ret)
{
return ret;
}
return OK;
}
ATCommandsInterface* UbloxModem::getATCommandsInterface()
{
return &m_at;
}
int UbloxModem::init()
{
if(m_atOpen)
{
return OK;
}
DBG("Starting AT thread if needed");
int ret = m_at.open();
if(ret)
{
return ret;
}
DBG("Sending initialisation commands");
ret = m_at.init(false);
if(ret)
{
return ret;
}
ATCommandsInterface::ATResult result;
CREGProcessor cregProcessor(m_gsm);
//Wait for network registration
do
{
DBG("Waiting for network registration");
ret = m_at.execute(cregProcessor.getAtCommand(), &cregProcessor, &result);
DBG("Result of command: Err code=%d\n", ret);
DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
if(cregProcessor.getStatus() == CREGProcessor::STATUS_REGISTERING)
{
Thread::wait(3000);
}
} while(cregProcessor.getStatus() == CREGProcessor::STATUS_REGISTERING);
if(cregProcessor.getStatus() == CREGProcessor::STATUS_FAILED)
{
ERR("Registration denied");
return NET_AUTH;
}
m_atOpen = true;
return OK;
}
int UbloxModem::cleanup()
{
if(m_ppp.isConnected())
{
WARN("Data connection is still open"); //Try to encourage good behaviour from the user
m_ppp.disconnect();
}
m_smsInit = false;
m_ussdInit = false;
m_linkMonitorInit = false;
//We don't reset m_ipInit as PPPIPInterface::init() only needs to be called once
if(m_atOpen)
{
m_at.close();
m_atOpen = false;
}
return OK;
}
int UbloxModem::sendUSSD(const char* command, char* result, size_t maxLength)
{
int ret = init();
if(ret)
{
return ret;
}
if(!m_ussdInit)
{
ret = m_ussd.init();
if(ret)
{
return ret;
}
m_ussdInit = true;
}
ret = m_ussd.send(command, result, maxLength);
if(ret)
{
return ret;
}
return OK;
}
int UbloxModem::getLinkState(int* pRssi, LinkMonitor::REGISTRATION_STATE* pRegistrationState, LinkMonitor::BEARER* pBearer)
{
int ret = init();
if(ret)
{
return ret;
}
if(!m_linkMonitorInit)
{
ret = m_linkMonitor.init();
if(ret)
{
return ret;
}
m_linkMonitorInit = true;
}
ret = m_linkMonitor.getState(pRssi, pRegistrationState, pBearer);
if(ret)
{
return ret;
}
return OK;
}
#include "USBHost.h"
#include "UbloxGSMModemInitializer.h"
#include "UbloxCDMAModemInitializer.h"
UbloxUSBModem::UbloxUSBModem() :
UbloxModem(&m_atStream, &m_pppStream),
m_dongle(), // Construct WANDongle: USB interface with two serial channels to the modem (USBSerialStream objects)
m_atStream(m_dongle.getSerial(1)), // AT commands are sent down one serial channel.
m_pppStream(m_dongle.getSerial(0)), // PPP connections are managed via another serial channel.
m_dongleConnected(false) // Dongle is initially not ready for anything
{
USBHost* host = USBHost::getHostInst();
m_dongle.addInitializer(new UbloxGSMModemInitializer(host));
m_dongle.addInitializer(new UbloxCDMAModemInitializer(host));
}
int UbloxUSBModem::init()
{
if( !m_dongleConnected )
{
m_dongleConnected = true;
while( !m_dongle.connected() )
{
m_dongle.tryConnect();
Thread::wait(10);
}
if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_UBLOX_LISAU200)
{
INFO("Using a u-blox LISA-U200 3G/WCDMA Modem");
}
else if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_UBLOX_LISAC200)
{
INFO("Using a u-blox LISA-C200 CDMA Modem");
m_gsm = false;
m_onePort = true;
}
else
{
WARN("Using an Unknown Dongle");
}
}
return UbloxModem::init();
}
int UbloxUSBModem::cleanup()
{
UbloxModem::cleanup();
m_dongle.disconnect();
m_dongleConnected = false;
return OK;
}
UbloxSerModem::UbloxSerModem() :
UbloxModem(&m_atStream, NULL),
m_Serial(P0_15,P0_16),
m_atStream(m_Serial)
{
m_Serial.baud(115200);
}

View File

@ -0,0 +1,168 @@
/* VodafoneUSBModem.h */
/* Copyright (C) 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 UBLOXMODEM_H_
#define UBLOXMODEM_H_
#include "core/fwk.h"
#include "at/ATCommandsInterface.h"
#include "ip/PPPIPInterface.h"
#include "sms/GSMSMSInterface.h"
#include "sms/CDMASMSInterface.h"
#include "ussd/USSDInterface.h"
#include "link/LinkMonitor.h"
#include "CellularModem.h"
/** u-blox WCDMA modem (LISA-U200)
*/
class UbloxModem: public CellularModem
{
public:
/** Create u-blox API instance
@param powerGatingPin Optional pin commanding a power gating transistor on the modem's power line
@param powerGatingOnWhenPinHigh true if the pin needs to be high to power the dongle, defaults to true
*/
UbloxModem(IOStream* atStream, IOStream* pppStream);
//Internet-related functions
/** Open a 3G internet connection
@return 0 on success, error code on failure
*/
virtual int connect(const char* apn = NULL, const char* user = NULL, const char* password = NULL);
/** Close the internet connection
@return 0 on success, error code on failure
*/
virtual int disconnect();
/** Send a SM
@param number The receiver's phone number
@param message The message to send
@return 0 on success, error code on failure
*/
virtual int sendSM(const char* number, const char* message);
/** Receive a SM
@param number Pointer to a buffer to store the sender's phone number (must be at least 17 characters-long, including the sapce for the null-terminating char)
@param message Pointer to a buffer to store the the incoming message
@param maxLength Maximum message length that can be stored in buffer (including null-terminating character)
@return 0 on success, error code on failure
*/
virtual int getSM(char* number, char* message, size_t maxLength);
/** Get the number of SMs in the incoming box
@param pCount pointer to store the number of unprocessed SMs on
@return 0 on success, error code on failure
*/
virtual int getSMCount(size_t* pCount);
/** Send a USSD command & wait for its result
@param command The command to send
@param result Buffer in which to store the result
@param maxLength Maximum result length that can be stored in buffer (including null-terminating character)
@return 0 on success, error code on failure
*/
int sendUSSD(const char* command, char* result, size_t maxLength);
/** Get link state
@param pRssi pointer to store the current RSSI in dBm, between -51 dBm and -113 dBm if known; -51 dBm means -51 dBm or more; -113 dBm means -113 dBm or less; 0 if unknown
@param pRegistrationState pointer to store the current registration state
@param pBearer pointer to store the current bearer
@return 0 on success, error code on failure
*/
int getLinkState(int* pRssi, LinkMonitor::REGISTRATION_STATE* pRegistrationState, LinkMonitor::BEARER* pBearer);
/** Get the ATCommandsInterface instance
@return Pointer to the ATCommandsInterface instance
*/
virtual ATCommandsInterface* getATCommandsInterface();
protected:
/** Initialise dongle.
* The following actions are performed:
* 1) Start AT interface thread
* 2) Wait for network registration
*/
virtual int init();
/** De-initialise dongle.
* The following actions are performed:
* 1) Tear down PPP session
* 2) Set SMS,USSD, and LinkMonitor subsystems to un-initialised
* 3) Close the AT commands interface
*/
virtual int cleanup();
private:
ATCommandsInterface m_at; //< Interface to AT commands processing
CDMASMSInterface m_CdmaSms; //< Interface to SMS manager (send/receive etc)
GSMSMSInterface m_GsmSms; //< Interface to SMS manager (send/receive etc)
USSDInterface m_ussd; //< Interface to USSD manager (send etc)
LinkMonitor m_linkMonitor; //< Interface to link monitor (RSSI)
PPPIPInterface m_ppp; //< Interface to PPP conection manager (IP assignment etc)
bool m_ipInit; //< Has PPIPInterface object (m_ppp) been initialised? true/false
bool m_smsInit; //< Has SMSInterface object (m_sms) been initialised? true/false
bool m_ussdInit; //< Has USSDInterface object (m_ussd) been initialised? true/false
bool m_linkMonitorInit; //< Has LinkMonitor object (m_linkMonitor) been initialised? true/false
bool m_atOpen; //< Is the interface to the ATCommandsInterface open? true/false
protected:
bool m_onePort;
bool m_gsm;
};
#include "WANDongle.h"
#include "serial/usb/USBSerialStream.h"
class UbloxUSBModem: public UbloxModem
{
public:
UbloxUSBModem();
virtual int init();
virtual int cleanup();
virtual int power(bool enable) { return 1; }
private:
WANDongle m_dongle; //< Interface to USB connected WAN dongle
USBSerialStream m_atStream; //< Serial interface to AT channel on modem
USBSerialStream m_pppStream; //< Serial interface to PPP channel on modem
bool m_dongleConnected; //< Is the dongle physically connected (does the USB stack respond)? true/false
};
#include "serial/io/IOSerialStream.h"
class UbloxSerModem: public UbloxModem
{
public:
UbloxSerModem();
virtual int power(bool enable) { return 1; }
private:
RawSerial m_Serial;
IOSerialStream m_atStream; //< Serial interface to AT channel on modem
};
#endif /* UBLOXMODEM_H_ */

View File

@ -33,7 +33,7 @@
UbloxUSBCDMAModem::UbloxUSBCDMAModem(PinName powerGatingPin /*= NC*/, bool powerGatingOnWhenPinHigh /* = true*/, int serial /* 0 */) : m_dongle(), UbloxUSBCDMAModem::UbloxUSBCDMAModem(PinName powerGatingPin /*= NC*/, bool powerGatingOnWhenPinHigh /* = true*/, int serial /* 0 */) : m_dongle(),
m_stream(m_dongle.getSerial(serial)), m_stream(m_dongle.getSerial(serial)),
m_at(&m_stream), m_at(&m_stream),
m_sms(&m_at), m_ppp(&m_stream, DEFAULT_MSISDN_CDMA), m_sms(&m_at), m_ppp(&m_stream),
m_dongleConnected(false), m_ipInit(false), m_smsInit(false), m_atOpen(false), m_dongleConnected(false), m_ipInit(false), m_smsInit(false), m_atOpen(false),
m_powerGatingPin(powerGatingPin), m_powerGatingOnWhenPinHigh(powerGatingOnWhenPinHigh) m_powerGatingPin(powerGatingPin), m_powerGatingOnWhenPinHigh(powerGatingOnWhenPinHigh)
{ {
@ -88,7 +88,7 @@ int UbloxUSBCDMAModem::connect(const char* apn, const char* user, const char* pa
m_ipInit = true; m_ipInit = true;
m_ppp.init(); m_ppp.init();
} }
m_ppp.setup(user, password); m_ppp.setup(user, password, DEFAULT_MSISDN_CDMA);
int ret = init(); int ret = init();
if(ret) if(ret)
@ -341,7 +341,7 @@ int UbloxUSBCDMAModem::init()
return ret; return ret;
} }
if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_UBLOXC200) if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_UBLOX_LISAC200)
{ {
INFO("Using a UBLOX C200 Dongle"); INFO("Using a UBLOX C200 Dongle");
} }

View File

@ -36,7 +36,7 @@ UbloxUSBGSMModem::UbloxUSBGSMModem(PinName powerGatingPin /*= NC*/, bool powerGa
m_sms(&m_at), // Construct SMSInterface with the ATCommandsInterface m_sms(&m_at), // Construct SMSInterface with the ATCommandsInterface
m_ussd(&m_at), // Construct USSDInterface with the ATCommandsInterface m_ussd(&m_at), // Construct USSDInterface with the ATCommandsInterface
m_linkMonitor(&m_at), // Construct LinkMonitor with the ATCommandsInterface m_linkMonitor(&m_at), // Construct LinkMonitor with the ATCommandsInterface
m_ppp(&m_pppStream, DEFAULT_MSISDN_GSM), // Construct PPPIPInterface with the PPP serial channel m_ppp(&m_pppStream), // Construct PPPIPInterface with the PPP serial channel
m_dongleConnected(false), // Dongle is initially not ready for anything m_dongleConnected(false), // Dongle is initially not ready for anything
m_ipInit(false), // PPIPInterface connection is initially down m_ipInit(false), // PPIPInterface connection is initially down
m_smsInit(false), // SMSInterface starts un-initialised m_smsInit(false), // SMSInterface starts un-initialised
@ -185,7 +185,7 @@ int UbloxUSBGSMModem::connect(const char* apn, const char* user, const char* pas
m_ipInit = true; m_ipInit = true;
m_ppp.init(); m_ppp.init();
} }
m_ppp.setup(user, password); m_ppp.setup(user, password, DEFAULT_MSISDN_GSM);
int ret = init(); int ret = init();
if(ret) if(ret)
@ -543,7 +543,7 @@ int UbloxUSBGSMModem::init()
return ret; return ret;
} }
if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_UBX) if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_UBLOX_LISAU200)
{ {
INFO("Using a u-blox LISA-U"); INFO("Using a u-blox LISA-U");
} }