A library for talking to Multi-Tech's Cellular SocketModem Devices.

Dependents:   M2X_dev axeda_wrapper_dev MTS_M2x_Example1 MTS_Cellular_Connect_Example ... more

Revision:
12:40ac31a09132
Parent:
11:134435d8a2d5
Child:
13:0af863114629
--- a/cellular/Cellular.cpp	Fri Dec 13 14:53:08 2013 +0000
+++ b/cellular/Cellular.cpp	Fri Dec 13 20:23:40 2013 +0000
@@ -2,8 +2,17 @@
 #define CELLULAR_CPP
 
 #include "Cellular.h"
+#include "MTSText.h"
+#include <sstream>
 
-Cellular::Cellular(MTSBufferedIO* io) : io(io)
+Cellular::Cellular(MTSBufferedIO& io) 
+: io(io)
+, code(OK)
+, pppConnected(false)
+, mode(TCP)
+, socketOpened(false)
+, local_port(0)
+, host_port(0)
 {
 }
 
@@ -11,9 +20,142 @@
 {
 }
 
-Cellular::Code Cellular::ATTest()
+bool Cellular::connect() {
+    //Run Test first to validate a good state
+    //Check RSSI: AT+CSQ    
+    //Check Registration: AT+CREG? == 0,1
+    
+    
+    //AT#CONNECTIONSTART: Make a PPP connection
+    std::string pppResult = sendCommand("AT#CONNECTIONSTART", 30000);
+    
+    size_t pos = 0;
+    std::string ip = Text::getLine(pppResult, pos, pos);
+    std::string status = Text::getLine(pppResult, pos, pos);
+    
+    return false;
+}
+
+void Cellular::disconnect() {
+    
+}
+
+bool Cellular::isConnected() {
+    //1) Check if APN was set
+    if(apn.size() == 0) {
+        printf("[DEBUG] APN is not set\n");
+        return false;
+    }
+    
+    //1) Check that we do not have a live connection up
+    if(socketOpened) {
+        printf("[DEBUG] Socket is opened\n");
+        return true;
+    }
+    //2) Query the radio
+    pppConnected = false;
+    std::string result = sendCommand("AT#VSTATE", 1000);
+    if(result.find("CONNECTED") != std::string::npos) {
+        pppConnected = true;
+    }
+    
+    return pppConnected;
+}
+
+bool Cellular::bind(unsigned int port) {
+    return false;
+}
+
+bool Cellular::open(const std::string& address, unsigned int port, Mode mode) {
+    Code portCode, addressCode;
+    
+    //1) Check that we do not have a live connection up
+    if(socketOpened) {
+        printf("[DEBUG] Socket already opened\n");
+        return true;
+    }
+    
+    //2) Check PPP connection
+    if(!isConnected()) {
+        printf("[ERROR] PPP not established.  Attempting to connect\n");
+        if(!connect()) {
+            printf("[ERROR] PPP connection failed\n");
+            return false;
+        } else {
+            printf("[DEBUG] PPP connection established\n");
+        }
+    }
+    
+    //Setup IP Connection
+    std::stringstream ss;    
+    if(mode == TCP) {
+        ss << "AT#TCPPORT=1," << port;
+        portCode = sendBasicCommand(ss.str(), 1000);
+        addressCode = sendBasicCommand("AT#TCPSERV=1," + address, 1000);
+    } else {
+        ss << "AT#UDPPORT=1," << port;
+        portCode = sendBasicCommand(ss.str(), 1000);
+        addressCode = sendBasicCommand("AT#UDPSERV=1," + address, 1000);
+    }
+    
+    if(portCode == OK) {
+        host_port = port;
+    } else {
+        printf("[ERROR] Host port could not be set\n");
+    }
+    
+    if(addressCode == OK) {
+        host_address = address;
+    } else {
+        printf("[ERROR] Host address could not be set\n");
+    }
+    
+    
+        
+    return false;
+}
+
+bool Cellular::isOpen() {
+    return false;
+}
+
+void Cellular::close() {
+    
+}
+
+int Cellular::read(char* data, int max, int timeout) {
+    return -1;
+}
+
+int Cellular::write(char* data, int length, int timeout) {
+    return -1;
+}
+
+unsigned int Cellular::readable() {
+    return 0;
+}
+
+unsigned int Cellular::writeable() {
+    return 0;
+}
+
+void Cellular::reset() {
+    
+}
+
+Cellular::Code Cellular::test()
 {
-    return sendBasicCommand("AT", 1000);
+    Code code = sendBasicCommand("AT", 1000);
+    
+    if(code != OK) {
+        printf("[Error] Failed basic AT command");
+        return code;
+    }
+
+    //AT#VSTATE != "CHECKING"
+    
+    //AT#GPRSMODE == 
+    return OK;
 }
 
 Cellular::Code Cellular::echoOff(bool state)
@@ -39,6 +181,10 @@
     return value;
 }
 
+std::string Cellular::getPhoneNumber() {
+    return "unknown";
+}
+
 Cellular::Registration Cellular::getRegistration()
 {
     string response = sendCommand("AT+CREG?", 1000);
@@ -64,38 +210,39 @@
         case 5:
             return ROAMING;
     }
+    return UNKNOWN;
 }
 
-int Cellular::connect(string host, int port)
-{
-    // Set the Server Address
-    string hostCmd = "AT#TCPSERV=1,\"";
-    hostCmd.append(host);
-    hostCmd.append("\"");
-    if (sendBasicCommand(hostCmd, 1000) != OK) {
-        return -1;
-    }
-
-    // Set the Server Port
-    string portCmd = "AT#TCPPORT=1,\"";
-    char tmp[7];
-    if (sprintf(tmp, "%d", port) < 0) {
-        return -1;
-    }
-    portCmd.append(string(tmp));
-    portCmd.append("\"");
-    if (sendBasicCommand(portCmd, 1000) != OK) {
-        return -1;
-    }
-
-    // Try and Connect
-    string response = sendCommand("AT#OTCP=1", 2000);
-    if (response.find("Ok_Info_WaitingForData") != string::npos) {
-        return 0;
-    } else {
-        return -1;
-    }
-}
+//int Cellular::connect(string host, int port)
+//{
+//    // Set the Server Address
+//    string hostCmd = "AT#TCPSERV=1,\"";
+//    hostCmd.append(host);
+//    hostCmd.append("\"");
+//    if (sendBasicCommand(hostCmd, 1000) != OK) {
+//        return -1;
+//    }
+//
+//    // Set the Server Port
+//    string portCmd = "AT#TCPPORT=1,\"";
+//    char tmp[7];
+//    if (sprintf(tmp, "%d", port) < 0) {
+//        return -1;
+//    }
+//    portCmd.append(string(tmp));
+//    portCmd.append("\"");
+//    if (sendBasicCommand(portCmd, 1000) != OK) {
+//        return -1;
+//    }
+//
+//    // Try and Connect
+//    string response = sendCommand("AT#OTCP=1", 2000);
+//    if (response.find("Ok_Info_WaitingForData") != string::npos) {
+//        return 0;
+//    } else {
+//        return -1;
+//    }
+//}
 
 Cellular::Code Cellular::sendBasicCommand(string command, int timeoutMillis, ESC_CHAR esc)
 {
@@ -111,7 +258,24 @@
     }
 }
 
-Cellular::Code Cellular::sendSMS(string phoneNumber, string message)
+Cellular::Code Cellular::setApn(const std::string& apn) {
+    Code code = sendBasicCommand("AT#APNSERV=\"" + apn + "\"", 1000);
+    if (code != OK) {
+        return code;
+    }
+    this->apn = apn;
+    return code;
+}
+
+Cellular::Code Cellular::setDns(const std::string& apn) {
+    return FAILURE;   
+}
+
+Cellular::Code Cellular::sendSMS(const Sms& sms) {
+    return sendSMS(sms.phoneNumber, sms.message);
+}
+
+Cellular::Code Cellular::sendSMS(const std::string& phoneNumber, const std::string& message)
 {
     Code code = sendBasicCommand("AT+CMGF=1", 1000);
     if (code != OK) {
@@ -126,13 +290,74 @@
     }
     wait(.2);
     string  response2 = sendCommand(message, 4000, CTRL_Z);
-    printf("SMS Response: %s\n", response2);
+    printf("SMS Response: %s\n", response2.c_str());
     if (response2.find("+CMGS:") == string::npos) {
         return FAILURE;
     }
     return OK;
 }
 
+std::vector<Cellular::Sms> Cellular::getReceivedSms() {
+    int smsNumber = 0;
+    std::vector<Sms> vSms;
+    std::string received = sendCommand("AT+CMGL=\"ALL\"", 4000);
+    size_t pos = received.find("+CMGL: ");
+    
+    while (pos != std::string::npos) {
+        Cellular::Sms sms;
+        std::string line(Text::getLine(received, pos, pos));
+        //printf("[DEBUG] Top of SMS Parse Loop. LINE[%s]\n", line.c_str());
+        if(line.find("+CMGL: ") == std::string::npos) {           
+            continue;
+        }
+        
+        //Start of SMS message
+        std::vector<std::string> vSmsParts = Text::split(line, ',');
+        if(vSmsParts.size() != 6) {
+            printf("[WARNING] Expected 6 commas. SMS[%d] DATA[%s]. Continuing ...\n", smsNumber, line.c_str());
+            continue;
+        }
+        
+        sms.phoneNumber = vSmsParts[2];
+        sms.timestamp = vSmsParts[4] + ", " + vSmsParts[5];
+        
+        if(pos == std::string::npos) {
+            printf("[WARNING] Expected SMS body. SMS[%d]. Leaving ...\n", smsNumber);
+            break;
+        }
+        //Check for the start of the next SMS message
+        size_t bodyEnd = received.find("\r\n+CMGL: ", pos);
+        if(bodyEnd == std::string::npos) {
+            //printf("[DEBUG] Parsing Last SMS. SMS[%d]\n", smsNumber);
+            //This must be the last SMS message
+            bodyEnd = received.find("\r\n\r\nOK", pos);
+        }
+        
+        //Safety check that we found the boundary of this current SMS message
+        if(bodyEnd != std::string::npos) {
+            sms.message = received.substr(pos, bodyEnd - pos);
+        } else {
+            sms.message = received.substr(pos);
+            printf("[WARNING] Expected to find end of SMS list. SMS[%d] DATA[%s].\n", smsNumber, sms.message.c_str());
+        }
+        vSms.push_back(sms);
+        pos = bodyEnd;
+        //printf("[DEBUG] Parsed SMS[%d].  Starting Next at position [%d]\n", smsNumber, pos);
+        smsNumber++;
+    }
+    printf("Received %d SMS\n", smsNumber);
+    return vSms;
+}
+
+Cellular::Code Cellular::deleteOnlyReceivedReadSms() {
+    return sendBasicCommand("AT+CMGD=1,1", 1000);
+}
+
+Cellular::Code Cellular::deleteAllReceivedSms() {
+    return sendBasicCommand("AT+CMGD=1,4", 1000);
+}
+
+
 string Cellular::sendCommand(string command, int timeoutMillis, ESC_CHAR esc)
 {
     int size = command.size() + 1;
@@ -144,21 +369,29 @@
         cmd[size -1] = 0x1A;
     }
 
-    io->rxClear();
-    io->txClear();
-    int status = io->write(cmd, size);
-    int available = io->rxAvailable();
+    io.rxClear();
+    io.txClear();
+    std::string result;
+    int status = io.write(cmd, size);
+    int available = io.rxAvailable();
     int previous = -1;
     int timer = 0;
-    while (available != previous && timer < timeoutMillis) {
+    char tmp[256];
+    tmp[255] = 0;
+    
+    do {
         wait(.1);
         timer = timer + 100;
         previous = available;
-        available = io->rxAvailable();
-    }
-    char tmp[available];
-    io->read(tmp, available);
-    return string(tmp);
+        available = io.rxAvailable();
+
+        int size = io.read(tmp,255);    //1 less than allocated
+        if(size > 0) {
+            result.append(tmp, size);
+        }
+    } while (available != previous && timer < timeoutMillis);
+    
+    return result;
 }
 
 #endif /* CELLULAR_CPP */
\ No newline at end of file