adding support for serial port

pull/121/head
mazgch 2013-12-09 21:22:02 +01:00
parent a3a16b3683
commit d0d4476659
15 changed files with 1021 additions and 58 deletions

View File

@ -63,30 +63,33 @@ int ATCommandsInterface::open()
}
//Initialize AT link & start events processing
int ATCommandsInterface::init()
int ATCommandsInterface::init(bool reset /* = true*/)
{
DBG("Sending ATZ E1 V1");
//Lock transaction mutex
m_transactionMtx.lock();
//Should we flush m_pStream at this point ???
int err;
int tries = 5;
do
if (reset)
{
err = executeInternal("ATZ E1 V1", this, NULL, 3000); //Enable echo and verbosity
if(err && tries)
DBG("Sending ATZ E1 V1");
//Should we flush m_pStream at this point ???
int err;
int tries = 5;
do
{
WARN("No response, trying again");
Thread::wait(1000); //Give dongle time to recover
err = executeInternal("ATZ E1 V1", this, NULL, 3000); //Enable echo and verbosity
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

View File

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

View File

@ -50,22 +50,15 @@ extern "C" {
#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();
}
/*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
@ -78,10 +71,11 @@ PPPIPInterface::PPPIPInterface(IOStream* pStream, const char* msisdn) : LwIPInte
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");
pppSetAuth(PPPAUTHTYPE_ANY, user, pw);
m_msisdn = msisdn;
DBG("Done");
return OK;
}
@ -89,22 +83,22 @@ int PPPIPInterface::setup(const char* user, const char* pw)
/*virtual*/ int PPPIPInterface::connect()
{
int ret;
char cmd[32];
int cmdLen;
char buf[32];
size_t len;
DBG("Trying to connect with PPP");
cleanupLink();
DBG("Sending %s", m_connectCmd);
ret = m_pStream->write((uint8_t*)m_connectCmd, strlen(m_connectCmd), osWaitForever);
cmdLen = sprintf(cmd, "%s%s%s", CONNECT_CMD_PREFIX, m_msisdn, CONNECT_CMD_SUFFIX);
DBG("Sending %s", cmd);
ret = m_pStream->write((uint8_t*)cmd, cmdLen, osWaitForever);
if( ret != OK )
{
return NET_UNKNOWN;
}
DBG("Expect %s", m_expectedResp);
len = 0;
size_t readLen;
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);
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
do //Clear buf
strcpy(&cmd[cmdLen], EXPECTED_RESP_SUFFIX);
if (strcmp(cmd, buf) != 0)
{
ret = m_pStream->read((uint8_t*)buf, &len, 32, 0);
} while( (ret == OK) && (len > 0) );
return NET_CONN;
}
//Discard buffer
do //Clear buf
{
ret = m_pStream->read((uint8_t*)buf, &len, 32, 0);
} while( (ret == OK) && (len > 0) );
return NET_CONN;
}
}
DBG("Transport link open");
if(datarate != 0)
{

View File

@ -40,11 +40,11 @@ using namespace rtos;
class PPPIPInterface : public LwIPInterface
{
public:
PPPIPInterface(IOStream* pStream, const char* msisdn);
PPPIPInterface(IOStream* pStream);
virtual ~PPPIPInterface();
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 disconnect();
@ -57,16 +57,13 @@ private:
IOStream* m_pStream; //Serial stream
bool m_streamAvail;
const char* m_msisdn;
int m_pppd;
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 void sio_read_abort(sio_fd_t fd);
char* m_connectCmd;
char* m_expectedResp;
char* m_expectedRespDatarate;
};
#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
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
{
public:
enum { CIRCBUF_SIZE = 127 }
USBSerialStream(IUSBHostSerial& serial);
/*virtual*/ ~USBSerialStream();

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,470 @@
/* 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;
}
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
bool m_onePort;
protected:
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(),
m_stream(m_dongle.getSerial(serial)),
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_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_ppp.init();
}
m_ppp.setup(user, password);
m_ppp.setup(user, password, DEFAULT_MSISDN_CDMA);
int ret = init();
if(ret)
@ -341,7 +341,7 @@ int UbloxUSBCDMAModem::init()
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");
}

View File

@ -36,7 +36,7 @@ UbloxUSBGSMModem::UbloxUSBGSMModem(PinName powerGatingPin /*= NC*/, bool powerGa
m_sms(&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(&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_ipInit(false), // PPIPInterface connection is initially down
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_ppp.init();
}
m_ppp.setup(user, password);
m_ppp.setup(user, password, DEFAULT_MSISDN_GSM);
int ret = init();
if(ret)
@ -543,7 +543,7 @@ int UbloxUSBGSMModem::init()
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");
}