Cellular library for MTS Socket Modem Arduino Shield devices from Multi-Tech Systems

Dependents:   mtsas mtsas mtsas mtsas

Files at this revision

API Documentation at this revision

Comitter:
Vanger
Date:
Thu Jun 26 21:12:37 2014 +0000
Parent:
24:32d29cdfc1fa
Child:
27:ec44d5a9544f
Commit message:
Made setApn() a pure virtual in Cellular.; Implemented setApn in both UIP and EasyIP; Implemented connect(), disconnect(), and ping() in EasyIP; Uncommented cell instantiation for EasyIP type models in CellularFactory

Changed in this revision

Cellular/Cellular.cpp Show annotated file Show diff for this revision Revisions of this file
Cellular/Cellular.h Show annotated file Show diff for this revision Revisions of this file
Cellular/CellularFactory.cpp Show annotated file Show diff for this revision Revisions of this file
Cellular/CellularFactory.h Show annotated file Show diff for this revision Revisions of this file
Cellular/EasyIP.cpp Show annotated file Show diff for this revision Revisions of this file
Cellular/EasyIP.h Show annotated file Show diff for this revision Revisions of this file
Cellular/UIP.cpp Show annotated file Show diff for this revision Revisions of this file
Cellular/UIP.h Show annotated file Show diff for this revision Revisions of this file
--- a/Cellular/Cellular.cpp	Mon Jun 23 14:33:01 2014 +0000
+++ b/Cellular/Cellular.cpp	Thu Jun 26 21:12:37 2014 +0000
@@ -132,21 +132,8 @@
     return UNKNOWN;
 }
 
-Code Cellular::setApn(const std::string& apn)
-{
-    if (type == MTSMC_H5_IP || type == MTSMC_H5 || type == MTSMC_G3) {
-        Code code = sendBasicCommand("AT#APNSERV=\"" + apn + "\"", 1000);
-        if (code != MTS_SUCCESS) {
-            return code;
-        }
-        this->apn = apn;
-        return code;
-    } else {
-        logInfo("CDMA radios don't need an APN");
-        return MTS_SUCCESS;
-    }
-}
-
+//Removed setAPN to be implemented in the individual cellular classes,
+//as UIP and EasyIP implement it in different ways.
 
 Code Cellular::setDns(const std::string& primary, const std::string& secondary)
 {
--- a/Cellular/Cellular.h	Mon Jun 23 14:33:01 2014 +0000
+++ b/Cellular/Cellular.h	Thu Jun 26 21:12:37 2014 +0000
@@ -197,8 +197,8 @@
     */
     virtual bool init(MTSBufferedIO* io);
     
-    /**
-    *
+    /** Sets up the physical connection pins
+    *   (DTR,DCD, and RESET obviously)
     */
     bool configureSignals(unsigned int DCD = NC, unsigned int DTR = NC, unsigned int RESET = NC);
 
@@ -234,7 +234,7 @@
     * @param the APN as a string.
     * @returns the standard AT Code enumeration.
     */
-    virtual Code setApn(const std::string& apn);
+    virtual Code setApn(const std::string& apn)=0;
 
     /** This method is used to set the DNS which enables the use of URLs instead
     * of IP addresses when making a socket connection.
--- a/Cellular/CellularFactory.cpp	Mon Jun 23 14:33:01 2014 +0000
+++ b/Cellular/CellularFactory.cpp	Thu Jun 26 21:12:37 2014 +0000
@@ -35,14 +35,15 @@
         wait(1);
     }
 
-    /* AT#VVERSION is a IUP specific AT command
+    /* AT#VVERSION is a UIP specific AT command
      * if we get an error response, we're not using a UIP board */
     reply = sendCommand(io, "AT#VVERSION", 2000);
-    if (reply.find("error") != string::npos) {
+    if (reply.find("ERROR") != string::npos) {
         uip = false;
     } else {
         uip = true;
     }
+    
 
     if (uip && model.find("HE910") != string::npos) {
         type = Cellular::MTSMC_H5_IP;
@@ -56,7 +57,7 @@
         type = Cellular::MTSMC_C2_IP;
         logDebug("radio model: CE910");
         cell = new UIP(type);
-    /*
+    
     } else if (model.find("HE910") != string::npos) {
         type = Cellular::MTSMC_H5;
         logDebug("radio model: HE910");
@@ -73,7 +74,7 @@
         type = Cellular::MTSMC_C2;
         logDebug("radio model: CE910");
         cell = new EasyIP(type);
-    */
+    
     } else {
         logError("cannot continue - could not determine radio type");
         return NULL;
--- a/Cellular/CellularFactory.h	Mon Jun 23 14:33:01 2014 +0000
+++ b/Cellular/CellularFactory.h	Thu Jun 26 21:12:37 2014 +0000
@@ -2,7 +2,7 @@
 #define CELLULARFACTORY_H
 
 #include "UIP.h"
-//#include "EasyIP.h"
+#include "EasyIP.h"
 #include "MTSBufferedIO.h"
 
 namespace mts {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Cellular/EasyIP.cpp	Thu Jun 26 21:12:37 2014 +0000
@@ -0,0 +1,265 @@
+// This is a template from UIP.cpp for now, will modify code and implement it as I go
+
+
+
+#include "mbed.h"
+#include "EasyIP.h"
+#include "MTSText.h"
+#include "MTSLog.h"
+#include "CellUtils.h"
+
+
+
+using namespace mts;
+
+EasyIP::EasyIP(Radio type)
+{
+    //Not sure how the construction process is done, 
+    //but assuming it works for both EasyIP and UIP the same way.
+    this->type = type;
+    io = NULL;
+    dcd = NULL;
+    dtr = NULL;
+    resetLine = NULL;
+    echoMode = true;
+    pppConnected = false;
+    socketMode = TCP;
+    socketOpened = false;
+    socketCloseable = true;
+    local_port = 0;
+    local_address = "";
+    host_port = 0;
+}
+
+EasyIP::~EasyIP()
+{
+    //Same reasoning for the destructor as the constructor,
+    //assuming it works for UIP, it will work for EasyIP
+    if (dtr != NULL) {
+        dtr->write(1);
+    }
+    
+    delete dcd;
+    delete dtr;
+    delete resetLine;
+}
+
+//Initializes the MTS IO Buffer
+bool EasyIP::init(MTSBufferedIO* io)
+{
+    if (! Cellular::init(io)) {
+        return false;
+    }
+
+    logDebug("radio type: %s", Cellular::getRadioNames(type).c_str());
+    return true;
+}
+
+bool EasyIP::connect()
+{
+    //Check if socket is open
+    //flag stored in Cellular.h
+    if(socketOpened) {
+        return true;
+    }
+
+    //Check if already connected
+    //by calling the function isConnected() in EasyIP.cpp
+    if(isConnected()) {
+        return true;
+    }
+    //Create an mbed timer object
+    Timer tmr;
+
+    //Check Registration: AT+CREG? == 0,1
+    //(Does the AT command inside Cellular class)
+    tmr.start();
+    do {
+        Registration registration = getRegistration();
+        if(registration != REGISTERED) {
+            logTrace("Not Registered [%d] ... waiting", (int)registration);
+            wait(1);
+        } else {
+            break;
+        }
+    } while(tmr.read() < 30);
+
+    //Check RSSI: AT+CSQ
+    //Does the command inside Cellular
+    tmr.reset();
+    do {
+        int rssi = getSignalStrength();
+        logDebug("Signal strength: %d", rssi);
+        if(rssi == 99) {
+            logTrace("No Signal ... waiting");
+            wait(1);
+        } else {
+            break;
+        }
+    } while(tmr.read() < 30);
+
+    //AT#CONNECTIONSTART: Make a PPP connection
+    if (type == MTSMC_H5 || type == MTSMC_G3) {
+        logDebug("Making PPP Connection Attempt. APN[%s]", apn.c_str());
+    } else {
+        logDebug("Making PPP Connection Attempt");
+    }
+    //The main thing going on; Sends the AT command to start a connection
+    //Assuming context is already stored in the modem...If not, will need to set context from classes/data
+    std::string pppResult = sendCommand("AT#SGACT=1,1", 120000);
+  
+    if(pppResult.find("OK") != std::string::npos) {
+        std::vector<std::string> parts = Text::split(pppResult, "\r\n");
+        if(parts.size() >= 2) {
+            parts = Text::split(parts[1], " ");
+            local_address = parts[1];
+        }
+        logInfo("PPP Connection Established: IP[%s]", local_address.c_str());
+        pppConnected = true;
+
+    } else {
+        pppConnected = false;
+    }
+
+    return pppConnected;
+}
+
+void EasyIP::disconnect()
+{
+    //AT#SGACT=1,0: Close a PPP connection
+    logDebug("Closing PPP Connection");
+
+    if(socketOpened) {
+        close(); //Calls another EasyIP 
+                 //function to close socket before disconnect
+    }
+    //Sends AT#SGACT=1,0 command
+    
+    if(sendBasicCommand("AT#SGACT=1,0", 10000) == MTS_SUCCESS) {
+        logDebug("Successfully closed PPP Connection");
+    } else {
+        logError("Closing PPP Connection. Continuing ...");
+    }
+    pppConnected = false; 
+}
+//++++++++++++++++++++++++++++++++++++++++++++
+bool EasyIP::isConnected()
+{
+    
+    return pppConnected;
+}
+//Binds the socket to a specific port if able
+bool EasyIP::bind(unsigned int port)
+{
+   
+   
+    return true;
+}
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+bool EasyIP::open(const std::string& address, unsigned int port, Mode mode)
+{
+   
+    return socketOpened;
+}
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++
+bool EasyIP::isOpen()
+{
+    
+    return socketOpened;
+}
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+bool EasyIP::close()
+{
+    
+    return true;
+}
+
+int EasyIP::read(char* data, int max, int timeout)
+{
+   
+    return 1;
+}
+
+int EasyIP::write(const char* data, int length, int timeout)
+{
+    
+    return 1;
+}
+
+unsigned int EasyIP::readable()
+{
+    
+    return io->readable();
+}
+
+unsigned int EasyIP::writeable()
+{
+    
+
+    return io->writeable();
+}
+
+bool EasyIP::setDeviceIP(std::string address)
+{
+    if (address.compare("DHCP") == 0) {
+        return true;
+    } else {
+        logWarning("Radio does not support static IPs, using DHCP.\n\r");
+        return false;
+    }
+}
+
+Code EasyIP::setApn(const std::string& apn)
+{
+    if (type == MTSMC_H5 || type == MTSMC_G3) {
+         //Set IP,PPP,IPv6
+        Code code = sendBasicCommand("AT+CGDCONT=1,PPP," + apn, 1000);
+        if (code != MTS_SUCCESS) {
+            return code;
+        }
+        this->apn = apn;
+        return code; //This will return MTS_SUCCESS
+    } else {
+        logInfo("CDMA radios don't need an APN");
+        return MTS_SUCCESS;
+    }
+}
+//++++++++++++++++++++++++++++++++++++++++++++++++++
+void EasyIP::reset()
+{
+}
+
+std::string EasyIP::getDeviceIP()
+{
+    return local_address;
+}
+
+//Turns off echo when it receives a 1, turns on when it receives anything else
+Code EasyIP::echo(bool state)
+{
+    return MTS_SUCCESS;
+}
+
+bool EasyIP::ping(const std::string& address)
+{
+    char buffer[256] = {0};
+    std::string response;
+    
+    //Sends "PINGNUM" of pings to "address" with a timeout of "PINGDELAY"
+    //AT command takes pingdelay as units of 100ms, so seconds would be 10 times bigger
+    //Concatenate parameters into one string
+    sprintf(buffer, "AT#PING=%s,%d,32,%d", address.c_str(), PINGNUM, (10*PINGDELAY));
+    response = sendCommand(buffer,PINGDELAY*10000);
+    if(response.find("OK") != std::string::npos) {
+        //Not sure if I need a wait here, or if it is included in the sendcommand wait time
+        return true;
+    }
+    
+
+    return false;
+}
+
+Code EasyIP::setSocketCloseable(bool enabled)
+{
+    return MTS_SUCCESS;
+}
--- a/Cellular/EasyIP.h	Mon Jun 23 14:33:01 2014 +0000
+++ b/Cellular/EasyIP.h	Thu Jun 26 21:12:37 2014 +0000
@@ -1,4 +1,97 @@
 #ifndef SMC_H
 #define SMC_H
 
+#include <string>
+#include <vector>
+
+#include "MTSBufferedIO.h"
+#include "Cellular.h"
+
+namespace mts
+{
+/** This is a class for communicating without a Multi-Tech Systems SocketModem iCell. Instead, 
+* it uses the hayes command set to implement the same commands and functions as the UIP class.
+* (See the UIP class and documentation, "UIP.h")
+* This class supports three main types of cellular radio interactions including:
+* configuration and status AT command processing, SMS processing, and TCP Socket
+* data connections. It should be noted that the radio can not process commands or
+* SMS messages while having an open data connection at the same time. The concurrent
+* capability may be added in a future release. This class also inherits from IPStack
+* providing a common set of commands for communication devices that have an onboard
+* IP Stack. It is also integrated with the standard mbed Sockets package and can therefore
+* be used seamlessly with clients and services built on top of this interface already within
+* the mbed library.
+* The default baud rate for the cellular radio is 115200 bps.
+*/
+class EasyIP : public Cellular     //Inherits from Cellular.
+{
+public:
+/** This static function is used to create or get a reference to a
+    * Cellular object. Cellular uses the singleton pattern, which means
+    * that you can only have one existing at a time. The first time you
+    * call getInstance this method creates a new uninitialized Cellular
+    * object and returns it. All future calls to this method will return
+    * a reference to the instance created during the first call. Note that
+    * you must call init on the returned instance before mnaking any other
+    * calls. If using this class's bindings to any of the Socket package
+    * classes like TCPSocketConnection, you must call this method and the
+    * init method on the returned object first, before even creating the
+    * other objects.
+    *
+    * @returns a reference to the single Cellular obect that has been created.
+    */
+    EasyIP(Radio type);
+
+    /** Destructs a Cellular object and frees all related resources.
+    */
+    ~EasyIP();
+
+    virtual bool init(MTSBufferedIO* io);
+
+    // Wifi connection based commands derived from CommInterface.h
+    virtual bool connect();
+    virtual void disconnect();
+    virtual bool isConnected();
+    virtual void reset();
+
+    // TCP and UDP Socket related commands
+    // For behavior of the following methods refer to IPStack.h documentation
+    virtual bool bind(unsigned int port);
+    virtual bool open(const std::string& address, unsigned int port, Mode mode);
+    virtual bool isOpen();
+    virtual bool close();
+    virtual int read(char* data, int max, int timeout = -1);    //-1 times for no timeout?
+    virtual int write(const char* data, int length, int timeout = -1);
+    virtual unsigned int readable();
+    virtual unsigned int writeable();
+    virtual bool ping(const std::string& address = "8.8.8.8"); //Can this default address be different?
+    virtual std::string getDeviceIP();
+    virtual bool setDeviceIP(std::string address = "DHCP");//What does this do? Run DHCP to configure the IP?
+    
+    //Sets the APN, also sets mode to IP, might need to change
+    virtual Code setApn(const std::string& apn);
+    /** A method for configuring command ehco capability on the radio. This command
+    * sets whether sent characters are echoed back from the radio, in which case you
+    * will receive back every command you send.
+    *
+    * @param state if true echo will be turned off, otherwise it will be turned on.
+    * @returns the standard AT Code enumeration.
+    */
+    Code echo(bool state);
+
+    /** This method can be used to trade socket functionality for performance.
+    * In order to enable a socket connection to be closed by the client side programtically,
+    * this class must process all read and write data on the socket to guard the special
+    * escape character used to close an open socket connection. It is recommened that you
+    * use the default of true unless the overhead of these operations is too significant.
+    *
+    * @param enabled set to true if you want the socket closeable, otherwise false. The default
+    * is true.
+    * @returns the standard AT Code enumeration.
+    */
+    Code setSocketCloseable(bool enabled = true);  //ETX closes socket (ETX and DLE in payload are escaped with DLE)
+};
+
+}
+
 #endif
--- a/Cellular/UIP.cpp	Mon Jun 23 14:33:01 2014 +0000
+++ b/Cellular/UIP.cpp	Thu Jun 26 21:12:37 2014 +0000
@@ -90,9 +90,10 @@
         logDebug("Making PPP Connection Attempt");
     }
     std::string pppResult = sendCommand("AT#CONNECTIONSTART", 120000);
-    std::vector<std::string> parts = Text::split(pppResult, "\r\n");
+    
 
     if(pppResult.find("Ok_Info_GprsActivation") != std::string::npos) {
+        std::vector<std::string> parts = Text::split(pppResult, "\r\n");
         if(parts.size() >= 2) {
             local_address = parts[1];
         }
@@ -165,6 +166,7 @@
     return pppConnected;
 }
 
+
 bool UIP::bind(unsigned int port)
 {
     if(socketOpened) {
@@ -528,6 +530,21 @@
     }
 }
 
+Code UIP::setApn(const std::string& apn)
+{
+    if (type == MTSMC_H5_IP) {
+        Code code = sendBasicCommand("AT#APNSERV=\"" + apn + "\"", 1000);
+        if (code != MTS_SUCCESS) {
+            return code;
+        }
+        this->apn = apn;
+        return code; //This will return MTS_SUCCESS
+    } else {
+        logInfo("CDMA radios don't need an APN");
+        return MTS_SUCCESS;
+    }
+}
+
 void UIP::reset()
 {
     disconnect();
--- a/Cellular/UIP.h	Mon Jun 23 14:33:01 2014 +0000
+++ b/Cellular/UIP.h	Thu Jun 26 21:12:37 2014 +0000
@@ -75,6 +75,9 @@
     virtual bool ping(const std::string& address = "8.8.8.8");
     virtual std::string getDeviceIP();
     virtual bool setDeviceIP(std::string address = "DHCP");
+    
+    /** A method for setting the APN */
+    virtual Code setApn(const std::string& apn);
 
     /** A method for configuring command ehco capability on the radio. This command
     * sets whether sent characters are echoed back from the radio, in which case you