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:
17:2d7c4ea7491b
Parent:
13:0af863114629
Child:
19:38794784e009
--- a/cellular/Cellular.cpp	Fri Dec 13 23:02:50 2013 +0000
+++ b/cellular/Cellular.cpp	Mon Dec 16 20:00:20 2013 +0000
@@ -3,7 +3,6 @@
 
 #include "Cellular.h"
 #include "MTSText.h"
-#include <sstream>
 
 Cellular::Cellular(MTSBufferedIO& io) 
 : io(io)
@@ -11,6 +10,7 @@
 , pppConnected(false)
 , mode(TCP)
 , socketOpened(false)
+, socketCloseable(false)
 , local_port(0)
 , host_port(0)
 {
@@ -33,31 +33,29 @@
     
     //Check RSSI: AT+CSQ    
     int rssi = getSignalStrength();
-    printf("[DEBUG] Signal strength: %d\n", rssi);
+    printf("[DEBUG] Signal strength: %d\r\n", rssi);
     
     //Check Registration: AT+CREG? == 0,1
     Registration registration = getRegistration();
     if(registration != REGISTERED) {
-        printf("[WARNING] Not Registered [%d]\n", (int)registration);    
+        printf("[WARNING] Not Registered [%d]\r\n", (int)registration);    
     }
     
     //AT#CONNECTIONSTART: Make a PPP connection
-    printf("[DEBUG] Making PPP Connection Attempt. APN[%s]\n", apn.c_str());
+    printf("[DEBUG] Making PPP Connection Attempt. APN[%s]\r\n", apn.c_str());
     std::string pppResult = sendCommand("AT#CONNECTIONSTART", 120000);
+    std::vector<std::string> parts = Text::split(pppResult, "\r\n");
     
-    printf("[DEBUG] PPP CONNECT RESULT [%s]\n", pppResult.c_str());
-           
-    std::vector<std::string> parts = Text::split(pppResult, "\r\n");
-    for(uint32_t i = 0; i < parts.size(); i++) {
-        printf("[%d] [%s]\r\n", i, parts[i].c_str());   
-    }
-    
+    //printf("[DEBUG] PPP CONNECT RESULT [%s]\r\n", pppResult.c_str());
+//    for(uint32_t i = 0; i < parts.size(); i++) {
+//        printf("[%d] [%s]\r\n", i, parts[i].c_str());   
+//    }
            
     if(pppResult.find("Ok_Info_GprsActivation") != std::string::npos) {
         if(parts.size() >= 2) {
             local_address = parts[1];   
         }
-        printf("[INFO] PPP Connection Established: IP[%s]\n", local_address.c_str());
+        printf("[INFO] PPP Connection Established: IP[%s]\r\n", local_address.c_str());
         pppConnected = true;
         
     } else {
@@ -68,19 +66,33 @@
 }
 
 void Cellular::disconnect() {
+    //AT#CONNECTIONSTOP: Close a PPP connection
+    printf("[DEBUG] Closing PPP Connection\r\n");
     
+    if(socketOpened) { 
+        close();   
+    }
+    
+    Code code = sendBasicCommand("AT#CONNECTIONSTOP", 10000);
+    if(code == OK) {
+        printf("[DEBUG] Successfully closed PPP Connection\r\n");
+    } else {
+        printf("[ERROR] Closing PPP Connection [%d].  Continuing ...\r\n", (int)code);   
+    }
+    
+    pppConnected = false;
 }
 
 bool Cellular::isConnected() {
     //1) Check if APN was set
     if(apn.size() == 0) {
-        printf("[DEBUG] APN is not set\n");
+        printf("[DEBUG] APN is not set\r\n");
         return false;
     }
     
     //1) Check that we do not have a live connection up
     if(socketOpened) {
-        printf("[DEBUG] Socket is opened\n");
+        printf("[DEBUG] Socket is opened\r\n");
         return true;
     }
     //2) Query the radio
@@ -98,56 +110,69 @@
 }
 
 bool Cellular::open(const std::string& address, unsigned int port, Mode mode) {
+    char buffer[256] = {0};
     Code portCode, addressCode;
+    printf("[DEBUG] Attempting to Open Socket\r\n");
     
     //1) Check that we do not have a live connection up
     if(socketOpened) {
-        printf("[DEBUG] Socket already opened\n");
+        printf("[DEBUG] Socket already opened\r\n");
         return true;
     }
     
     //2) Check PPP connection
     if(!isConnected()) {
-        printf("[ERROR] PPP not established.  Attempting to connect\n");
+        printf("[ERROR] PPP not established.  Attempting to connect\r\n");
         if(!connect()) {
-            printf("[ERROR] PPP connection failed\n");
+            printf("[ERROR] PPP connection failed\r\n");
             return false;
         } else {
-            printf("[DEBUG] PPP connection established\n");
+            printf("[DEBUG] PPP connection established\r\n");
         }
     }
     
-    //Setup IP Connection
-    std::stringstream ss;    
+    ////Setup IP Connection
     if(mode == TCP) {
-        ss << "AT#TCPPORT=1," << port;
-        portCode = sendBasicCommand(ss.str(), 1000);
-        addressCode = sendBasicCommand("AT#TCPSERV=1," + address, 1000);
+        if(socketCloseable) {
+            Code code = sendBasicCommand("AT#DLEMODE=1,0", 1000);
+            if(code != OK) {
+                printf("[WARNING] Unable to set socket closeable [%d]\r\n", (int) code);       
+            }
+        }
+        sprintf(buffer, "AT#TCPPORT=1,%d", port);
+        portCode = sendBasicCommand(buffer, 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(socketCloseable) {
+            Code code = sendBasicCommand("AT#UDPDLEMODE=1", 1000);
+            if(code != OK) {
+                printf("[WARNING] Unable to set socket closeable [%d]\r\n", (int) code);       
+            }
+        }
+        sprintf(buffer, "AT#UDPPORT=1,%d", port);
+        portCode = sendBasicCommand(buffer, 1000);
+        addressCode = sendBasicCommand("AT#UDPSERV=1,\"" + address + "\"", 1000);
     }
     
     if(portCode == OK) {
         host_port = port;
     } else {
-        printf("[ERROR] Host port could not be set\n");
+        printf("[ERROR] Host port could not be set\r\n");
     }
     
     if(addressCode == OK) {
         host_address = address;
     } else {
-        printf("[ERROR] Host address could not be set\n");
+        printf("[ERROR] Host address could not be set\r\n");
     }
     
     // Try and Connect
     string response = sendCommand("AT#OTCP=1", 30000);
     if (response.find("Ok_Info_WaitingForData") != string::npos) {
-        printf("[INFO] Opened TCP Socket [%s:%d]\n", address.c_str(), port);
+        printf("[INFO] Opened TCP Socket [%s:%d]\r\n", address.c_str(), port);
         socketOpened = true;
     } else {
-        printf("[WARNING] Unable to open TCP Socket [%s:%d]\n", address.c_str(), port);
+        printf("[WARNING] Unable to open TCP Socket [%s:%d]\r\n", address.c_str(), port);
         socketOpened = false;
     }
         
@@ -155,38 +180,100 @@
 }
 
 bool Cellular::isOpen() {
-    return false;
+    return socketOpened;
 }
 
-void Cellular::close() {
+bool Cellular::close() {
     if(!socketOpened) {
-        return;
+        printf("[ERROR] Socket is not open\r\n");
+        return false;
     }
     
-    //Build Escape Message => DLE ETX
-    char buffer[3] = { 0x10, 0x03, 0x00 };
+    if(!socketCloseable) {
+        printf("[ERROR] Socket is not closeable\r\n");
+        return false;
+    }
+    
+    //Build Escape Message => ETX
+    char buffer[2] = { 0x03, 0x00 };
     Code code = sendBasicCommand(buffer, 1000, NONE);
     if(code != OK) {
-        printf("[WARNING] Radio did not accept close socket command");
-        //Handle cleanup   
+        printf("[ERROR] Radio did not accept close socket command");
+        return false;
     }
-    socketOpened = false;    
+    socketOpened = false;
+    return true;
 }
 
 int Cellular::read(char* data, int max, int timeout) {
-    return -1;
+    if(!socketOpened) {
+        printf("[ERROR] Socket is not open\r\n");
+        return -1;
+    }
+    int bytesRead = 0;
+
+    if(timeout >= 0) {
+        Timer tmr;
+        tmr.start();
+        while (tmr.read_ms() <= timeout && bytesRead < max) {
+            if (io.readable()) {
+                if(io.read(data[bytesRead]) == 1) {
+                    bytesRead++;   
+                }
+            } else {
+                wait(0.05);   
+            }
+        }
+    } else {
+        bytesRead = io.read(data, max);
+    }
+    
+    return bytesRead;
 }
 
 int Cellular::write(char* data, int length, int timeout) {
-    return -1;
+    if(!socketOpened) {
+        printf("[ERROR] Socket is not open\r\n");
+        return -1;
+    }
+    
+    int bytesWritten = 0;
+    
+    if(timeout >= 0) {
+        Timer tmr;
+        tmr.start();
+        while (tmr.read_ms() <= timeout && bytesWritten < length) {
+            if (io.writeable()) {
+                if(io.write(*data) == 1) {
+                    data++;
+                    bytesWritten++;
+                }
+            } else {
+                wait(0.05);
+            }
+        }
+    } else {
+        bytesWritten = io.write(data, length);
+    }
+    
+    return bytesWritten;
 }
 
 unsigned int Cellular::readable() {
-    return 0;
+    if(!socketOpened) {
+        printf("[ERROR] Socket is not open\r\n");
+        return 0;
+    }
+    return io.readable();
 }
 
 unsigned int Cellular::writeable() {
-    return 0;
+    if(!socketOpened) {
+        printf("[ERROR] Socket is not open\r\n");
+        return 0;
+    }
+    
+    return io.writeable();
 }
 
 void Cellular::reset() {
@@ -269,6 +356,11 @@
 
 Cellular::Code Cellular::sendBasicCommand(string command, int timeoutMillis, ESC_CHAR esc)
 {
+    if(socketOpened) {
+        printf("[ERROR] socket is open. Can not send AT commands\r\n");    
+        return ERROR;
+    }
+
     string response = sendCommand(command, timeoutMillis, esc);
     if (response.size() == 0) {
         return NO_RESPONSE;
@@ -294,12 +386,27 @@
     return FAILURE;   
 }
 
+Cellular::Code Cellular::setSocketCloseable(bool enabled) {
+    if(socketCloseable == enabled) {
+        return OK;    
+    }
+    
+    if(socketOpened) {
+        printf("[ERROR] socket is already opened. Can not set closeable\r\n");    
+        return ERROR;
+    }
+    
+    socketCloseable = enabled;
+    
+    return OK;
+}
+
 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) {
         return code;
@@ -313,7 +420,7 @@
     }
     wait(.2);
     string  response2 = sendCommand(message, 4000, CTRL_Z);
-    printf("SMS Response: %s\n", response2.c_str());
+    printf("SMS Response: %s\r\n", response2.c_str());
     if (response2.find("+CMGS:") == string::npos) {
         return FAILURE;
     }
@@ -329,7 +436,7 @@
     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());
+        //printf("[DEBUG] Top of SMS Parse Loop. LINE[%s]\r\n", line.c_str());
         if(line.find("+CMGL: ") == std::string::npos) {           
             continue;
         }
@@ -337,7 +444,7 @@
         //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());
+            printf("[WARNING] Expected 6 commas. SMS[%d] DATA[%s]. Continuing ...\r\n", smsNumber, line.c_str());
             continue;
         }
         
@@ -345,13 +452,13 @@
         sms.timestamp = vSmsParts[4] + ", " + vSmsParts[5];
         
         if(pos == std::string::npos) {
-            printf("[WARNING] Expected SMS body. SMS[%d]. Leaving ...\n", smsNumber);
+            printf("[WARNING] Expected SMS body. SMS[%d]. Leaving ...\r\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);
+            //printf("[DEBUG] Parsing Last SMS. SMS[%d]\r\n", smsNumber);
             //This must be the last SMS message
             bodyEnd = received.find("\r\n\r\nOK", pos);
         }
@@ -361,14 +468,14 @@
             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());
+            printf("[WARNING] Expected to find end of SMS list. SMS[%d] DATA[%s].\r\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);
+        //printf("[DEBUG] Parsed SMS[%d].  Starting Next at position [%d]\r\n", smsNumber, pos);
         smsNumber++;
     }
-    printf("Received %d SMS\n", smsNumber);
+    printf("Received %d SMS\r\n", smsNumber);
     return vSms;
 }
 
@@ -383,6 +490,11 @@
 
 string Cellular::sendCommand(string command, int timeoutMillis, ESC_CHAR esc)
 {
+    if(socketOpened) {
+        printf("[ERROR] socket is open. Can not send AT commands\r\n");    
+        return "";
+    }
+
     int size = command.size() + 1;
     char cmd[size];
     strcpy(cmd, command.c_str());
@@ -425,7 +537,7 @@
             done =  (available == previous);
         }
         if(timer >= timeoutMillis) {
-            printf("[WARNING] sendCommand timed out after %d milliseconds\n", timeoutMillis);
+            printf("[WARNING] sendCommand timed out after %d milliseconds\r\n", timeoutMillis);
             done = true;
         }
     } while (!done);