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

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Cellular.cpp Source File

Cellular.cpp

00001 /* Universal Socket Modem Interface Library
00002 * Copyright (c) 2013 Multi-Tech Systems
00003 *
00004 * Licensed under the Apache License, Version 2.0 (the "License");
00005 * you may not use this file except in compliance with the License.
00006 * You may obtain a copy of the License at
00007 *
00008 *     http://www.apache.org/licenses/LICENSE-2.0
00009 *
00010 * Unless required by applicable law or agreed to in writing, software
00011 * distributed under the License is distributed on an "AS IS" BASIS,
00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013 * See the License for the specific language governing permissions and
00014 * limitations under the License.
00015 */
00016 
00017 
00018 #include "Cellular.h"
00019 #include "MTSText.h"
00020 #include "MTSSerial.h"
00021 
00022 using namespace mts;
00023 
00024 Cellular* Cellular::instance = NULL;
00025 
00026 Cellular* Cellular::getInstance()
00027 {
00028     if(instance == NULL) {
00029         instance = new Cellular(NULL);
00030     }
00031     return instance;
00032 }
00033 
00034 Cellular::Cellular(MTSBufferedIO* io)
00035     : io(io)
00036     , echoMode(true)
00037     , pppConnected(false)
00038     , mode(TCP)
00039     , socketOpened(false)
00040     , socketCloseable(true)
00041     , local_port(0)
00042     , local_address("")
00043     , host_port(0)
00044     , dcd(NULL)
00045     , dtr(NULL)
00046 {
00047 }
00048 
00049 Cellular::~Cellular()
00050 {
00051     if (dtr != NULL) {
00052         dtr->write(1);
00053     }
00054 
00055     delete dcd;
00056     delete dtr;
00057 }
00058 
00059 bool Cellular::init(MTSBufferedIO* io, PinName DCD, PinName DTR)
00060 {
00061     if (io == NULL) {
00062         return false;
00063     }
00064 
00065     if(dcd) {
00066         delete dcd;
00067         dcd = NULL;
00068     }
00069     if(dtr) {
00070         delete dtr;
00071         dtr = NULL;
00072     }
00073 
00074     if (DCD != NC) {
00075         // the radio will raise and lower this line
00076         dcd = new DigitalIn(DCD); //PTA4 - KL46
00077     }
00078     if (DTR != NC) {
00079         dtr = new DigitalOut(DTR); //PTC9 - KL46
00080         /* This line should be lowered when we want to talk to the radio and raised when we're done
00081         for now we will lower it in the constructor and raise it in the destructor
00082         */
00083         dtr->write(0);
00084     }
00085     instance->io = io;
00086 
00087     test();
00088     // Reset radio to make sure it's in a good state and wait for it to come back
00089     reset();
00090     test();
00091 
00092     return MTS_SUCCESS;
00093 }
00094 
00095 
00096 bool Cellular::connect()
00097 {
00098     //Check if socket is open
00099     if(socketOpened) {
00100         return true;
00101     }
00102 
00103     //Check if already connected
00104     if(isConnected()) {
00105         return true;
00106     }
00107 
00108     Timer tmr;
00109 
00110     //Check Registration: AT+CREG? == 0,1
00111     tmr.start();
00112     do {
00113         Registration registration = getRegistration();
00114         if(registration != REGISTERED) {
00115             printf("[WARNING] Not Registered [%d] ... waiting\r\n", (int)registration);
00116             wait(1);
00117         } else {
00118             break;
00119         }
00120     } while(tmr.read() < 30);
00121 
00122     //Check RSSI: AT+CSQ
00123     tmr.reset();
00124     do {
00125         int rssi = getSignalStrength();
00126         printf("[DEBUG] Signal strength: %d\r\n", rssi);
00127         if(rssi == 99) {
00128             printf("[WARNING] No Signal ... waiting\r\n");
00129             wait(1);
00130         } else {
00131             break;
00132         }
00133     } while(tmr.read() < 30);
00134 
00135     //AT#CONNECTIONSTART: Make a PPP connection
00136     printf("[DEBUG] Making PPP Connection Attempt. APN[%s]\r\n", apn.c_str());
00137     std::string pppResult = sendCommand("AT#CONNECTIONSTART", 120000);
00138     std::vector<std::string> parts = Text::split(pppResult, "\r\n");
00139 
00140     if(pppResult.find("Ok_Info_GprsActivation") != std::string::npos) {
00141         if(parts.size() >= 2) {
00142             local_address = parts[1];
00143         }
00144         printf("[INFO] PPP Connection Established: IP[%s]\r\n", local_address.c_str());
00145         pppConnected = true;
00146 
00147     } else {
00148         pppConnected = false;
00149     }
00150 
00151     return pppConnected;
00152 }
00153 
00154 void Cellular::disconnect()
00155 {
00156     //AT#CONNECTIONSTOP: Close a PPP connection
00157     printf("[DEBUG] Closing PPP Connection\r\n");
00158 
00159     if(socketOpened) {
00160         close();
00161     }
00162 
00163     Code code = sendBasicCommand("AT#CONNECTIONSTOP", 10000);
00164     if(code == MTS_SUCCESS) {
00165         printf("[DEBUG] Successfully closed PPP Connection\r\n");
00166     } else {
00167         printf("[ERROR] Closing PPP Connection [%d].  Continuing ...\r\n", (int)code);
00168     }
00169 
00170     pppConnected = false;
00171 }
00172 
00173 bool Cellular::isConnected()
00174 {
00175     //1) Check if APN was set
00176     if(apn.size() == 0) {
00177         printf("[DEBUG] APN is not set\r\n");
00178         return false;
00179     }
00180 
00181     //1) Check that we do not have a live connection up
00182     if(socketOpened) {
00183         printf("[DEBUG] Socket is opened\r\n");
00184         return true;
00185     }
00186     //2) Query the radio
00187     std::string result = sendCommand("AT#VSTATE", 3000);
00188     if(result.find("CONNECTED") != std::string::npos) {
00189         if(pppConnected == false) {
00190             printf("[WARNING] Internal PPP state tracking differs from radio (DISCONNECTED:CONNECTED)\r\n");
00191         }
00192         pppConnected = true;
00193     } else {
00194         if(pppConnected == true) {
00195             //Find out what state is
00196             size_t pos = result.find("STATE:");
00197             if(pos != std::string::npos) {
00198                 result = Text::getLine(result, pos + sizeof("STATE:"), pos);
00199                 printf("[WARNING] Internal PPP state tracking differs from radio (CONNECTED:%s)\r\n", result.c_str());
00200             } else {
00201                 printf("[ERROR] Unable to parse radio state: [%s]\r\n", result.c_str());
00202             }
00203 
00204         }
00205         pppConnected = false;
00206     }
00207 
00208     return pppConnected;
00209 }
00210 
00211 bool Cellular::bind(unsigned int port)
00212 {
00213     if(socketOpened) {
00214         printf("[ERROR] socket is open. Can not set local port\r\n");
00215         return false;
00216     }
00217     if(port > 65535) {
00218         printf("[ERROR] port out of range (0-65535)\r\n");
00219         return false;
00220     }
00221     local_port = port;
00222     return true;
00223 }
00224 
00225 bool Cellular::open(const std::string& address, unsigned int port, Mode mode)
00226 {
00227     char buffer[256] = {0};
00228     Code portCode, addressCode;
00229 
00230     //1) Check that we do not have a live connection up
00231     if(socketOpened) {
00232         //Check that the address, port, and mode match
00233         if(host_address != address || host_port != port || this->mode != mode) {
00234             if(this->mode == TCP) {
00235                 printf("[ERROR] TCP socket already opened [%s:%d]\r\n", host_address.c_str(), host_port);
00236             } else {
00237                 printf("[ERROR] UDP socket already opened [%s:%d]\r\n", host_address.c_str(), host_port);
00238             }
00239             return false;
00240         }
00241 
00242         printf("[DEBUG] Socket already opened\r\n");
00243         return true;
00244     }
00245 
00246     //2) Check Parameters
00247     if(port > 65535) {
00248         printf("[ERROR] port out of range (0-65535)\r\n");
00249         return false;
00250     }
00251 
00252     //3) Check PPP connection
00253     if(!isConnected()) {
00254         printf("[ERROR] PPP not established.  Attempting to connect\r\n");
00255         if(!connect()) {
00256             printf("[ERROR] PPP connection failed\r\n");
00257             return false;
00258         } else {
00259             printf("[DEBUG] PPP connection established\r\n");
00260         }
00261     }
00262 
00263     //Set Local Port
00264     if(local_port != 0) {
00265         //Attempt to set local port
00266         sprintf(buffer, "AT#OUTPORT=%d", local_port);
00267         Code code = sendBasicCommand(buffer, 1000);
00268         if(code != MTS_SUCCESS) {
00269             printf("[WARNING] Unable to set local port (%d) [%d]\r\n", local_port, (int) code);
00270         }
00271     }
00272 
00273     //Set TCP/UDP parameters
00274     if(mode == TCP) {
00275         if(socketCloseable) {
00276             Code code = sendBasicCommand("AT#DLEMODE=1,1", 1000);
00277             if(code != MTS_SUCCESS) {
00278                 printf("[WARNING] Unable to set socket closeable [%d]\r\n", (int) code);
00279             }
00280         }
00281         sprintf(buffer, "AT#TCPPORT=1,%d", port);
00282         portCode = sendBasicCommand(buffer, 1000);
00283         addressCode = sendBasicCommand("AT#TCPSERV=1,\"" + address + "\"", 1000);
00284     } else {
00285         if(socketCloseable) {
00286             Code code = sendBasicCommand("AT#UDPDLEMODE=1", 1000);
00287             if(code != MTS_SUCCESS) {
00288                 printf("[WARNING] Unable to set socket closeable [%d]\r\n", (int) code);
00289             }
00290         }
00291         sprintf(buffer, "AT#UDPPORT=%d", port);
00292         portCode = sendBasicCommand(buffer, 1000);
00293         addressCode = sendBasicCommand("AT#UDPSERV=\"" + address + "\"", 1000);
00294     }
00295 
00296     if(portCode == MTS_SUCCESS) {
00297         host_port = port;
00298     } else {
00299         printf("[ERROR] Host port could not be set\r\n");
00300     }
00301 
00302     if(addressCode == MTS_SUCCESS) {
00303         host_address = address;
00304     } else {
00305         printf("[ERROR] Host address could not be set\r\n");
00306     }
00307 
00308     // Try and Connect
00309     std::string sMode;
00310     std::string sOpenSocketCmd;
00311     if(mode == TCP) {
00312         sOpenSocketCmd = "AT#OTCP=1";
00313         sMode = "TCP";
00314     } else {
00315         sOpenSocketCmd = "AT#OUDP";
00316         sMode = "UDP";
00317     }
00318 
00319     string response = sendCommand(sOpenSocketCmd, 30000);
00320     if (response.find("Ok_Info_WaitingForData") != string::npos) {
00321         printf("[INFO] Opened %s Socket [%s:%d]\r\n", sMode.c_str(), address.c_str(), port);
00322         socketOpened = true;
00323     } else {
00324         printf("[WARNING] Unable to open %s Socket [%s:%d]\r\n", sMode.c_str(),  address.c_str(), port);
00325         socketOpened = false;
00326     }
00327 
00328     return socketOpened;
00329 }
00330 
00331 bool Cellular::isOpen()
00332 {
00333     if(io->readable()) {
00334         printf("[DEBUG] Assuming open, data available to read.\n\r");
00335         return true;
00336     }
00337     return socketOpened;
00338 }
00339 
00340 bool Cellular::close()
00341 {
00342     if(io == NULL) {
00343         printf("[ERROR] MTSBufferedIO not set\r\n");
00344         return false;
00345     }
00346 
00347     if(!socketOpened) {
00348         printf("[WARNING] Socket close() called, but socket was not open\r\n");
00349         return true;
00350     }
00351 
00352     if(!socketCloseable) {
00353         printf("[ERROR] Socket is not closeable\r\n");
00354         return false;
00355     }
00356 
00357 
00358 
00359     if(io->write(ETX, 1000) != 1) {
00360         printf("[ERROR] Timed out attempting to close socket\r\n");
00361         return false;
00362     }
00363 
00364     Timer tmr;
00365     int counter = 0;
00366     char tmp[256];
00367     tmr.start();
00368     do {
00369         if(socketOpened == false) {
00370             break;
00371         }
00372         read(tmp, 256, 1000);
00373     } while(counter++ < 10);
00374 
00375     io->rxClear();
00376     io->txClear();
00377 
00378     socketOpened = false;
00379     return true;
00380 }
00381 
00382 int Cellular::read(char* data, int max, int timeout)
00383 {
00384     if(io == NULL) {
00385         printf("[ERROR] MTSBufferedIO not set\r\n");
00386         return -1;
00387     }
00388 
00389     //Check that nothing is in the rx buffer
00390     if(!socketOpened && !io->readable()) {
00391         printf("[ERROR] Socket is not open\r\n");
00392         return -1;
00393     }
00394 
00395     int bytesRead = 0;
00396 
00397     if(timeout >= 0) {
00398         bytesRead = io->read(data, max, static_cast<unsigned int>(timeout));
00399     } else {
00400         bytesRead = io->read(data, max);
00401     }
00402 
00403     if(bytesRead > 0 && socketCloseable) {
00404         //Remove escape characters
00405         int index = 0;
00406         bool escapeFlag = false;
00407         for(int i = 0; i < bytesRead; i++) {
00408             if(data[i] == DLE || data[i] == ETX) {
00409                 if(escapeFlag == true) {
00410                     //This character has been escaped
00411                     escapeFlag = false;
00412                 } else if(data[bytesRead] == DLE) {
00413                     //Found escape character
00414                     escapeFlag = true;
00415                     continue;
00416                 } else {
00417                     //ETX sent without escape -> Socket closed
00418                     printf("[INFO] Read ETX character without DLE escape. Socket closed\r\n");
00419                     socketOpened = false;
00420                     continue;
00421                 }
00422             }
00423 
00424             if(index != i) {
00425                 data[index] = data[i];
00426             }
00427             index++;
00428         }
00429         bytesRead = index;
00430     }
00431 
00432     //Scan for socket closed message
00433     for(size_t i = 0; i < bytesRead; i++) {
00434         if(data[i] == 'O') {
00435             if(strstr(&data[i], "Ok_Info_SocketClosed")) {
00436                 printf("[INFO] Found socket closed message. Socket closed\r\n");
00437                 //Close socket and Cut Off End of Message
00438                 socketOpened = false;
00439                 data[i] = '\0';
00440                 bytesRead = i;
00441                 break;
00442             }
00443         }
00444     }
00445     return bytesRead;
00446 }
00447 
00448 int Cellular::write(const char* data, int length, int timeout)
00449 {
00450     if(io == NULL) {
00451         printf("[ERROR] MTSBufferedIO not set\r\n");
00452         return -1;
00453     }
00454 
00455     if(!socketOpened) {
00456         printf("[ERROR] Socket is not open\r\n");
00457         return -1;
00458     }
00459 
00460     //In order to avoid allocating another buffer, capture indices of
00461     //characters to escape during write
00462     int specialWritten = 0;
00463     std::vector<int> vSpecial;
00464     if(socketCloseable) {
00465         for(int i = 0; i < length; i++) {
00466             if(data[i] == ETX || data[i] == DLE) {
00467                 //Push back index of special characters
00468                 vSpecial.push_back(i);
00469             }
00470         }
00471     }
00472 
00473     int bytesWritten = 0;
00474     if(timeout >= 0) {
00475         Timer tmr;
00476         tmr.start();
00477         do {
00478             int available = io->writeable();
00479             if (available > 0) {
00480                 if(specialWritten < vSpecial.size()) {
00481                     //Check if current index is at a special character
00482                     if(bytesWritten == vSpecial[specialWritten]) {
00483                         if(available < 2) {
00484                             //Requires at least two bytes of space
00485                             wait(0.05);
00486                             continue;
00487                         }
00488                         //Ready to write special character
00489                         if(io->write(DLE)) {
00490                             specialWritten++;
00491                             if(io->write(data[bytesWritten])) {
00492                                 bytesWritten++;
00493                             }
00494                         } else {
00495                             //Unable to write escape character, try again next round
00496                             wait(0.05);
00497                         }
00498                     } else {
00499                         //We want to write all the way up to the next special character
00500                         int relativeIndex = vSpecial[specialWritten] - bytesWritten;
00501                         int size = MIN(available, relativeIndex);
00502                         bytesWritten += io->write(&data[bytesWritten], size);
00503                     }
00504                 } else {
00505                     int size = MIN(available, length - bytesWritten);
00506                     bytesWritten += io->write(&data[bytesWritten], size);
00507                 }
00508             } else {
00509                 wait(0.05);
00510             }
00511         } while (tmr.read_ms() <= timeout && bytesWritten < length);
00512     } else {
00513         for(int i = 0; i < vSpecial.size(); i++) {
00514             //Write up to the special character, then write the special character
00515             int size = vSpecial[i] - bytesWritten;
00516             int currentWritten = io->write(&data[bytesWritten], size);
00517             bytesWritten += currentWritten;
00518             if(currentWritten != size) {
00519                 //Failed to write up to the special character.
00520                 return bytesWritten;
00521             }
00522             if(io->write(DLE) && io->write(data[bytesWritten])) {
00523                 bytesWritten++;
00524             } else {
00525                 //Failed to write the special character.
00526                 return bytesWritten;
00527             }
00528         }
00529 
00530         bytesWritten = io->write(&data[bytesWritten], length - bytesWritten);
00531     }
00532 
00533     return bytesWritten;
00534 }
00535 
00536 unsigned int Cellular::readable()
00537 {
00538     if(io == NULL) {
00539         printf("[WARNING] MTSBufferedIO not set\r\n");
00540         return 0;
00541     }
00542     if(!socketOpened && !io->readable()) {
00543         printf("[WARNING] Socket is not open\r\n");
00544         return 0;
00545     }
00546     return io->readable();
00547 }
00548 
00549 unsigned int Cellular::writeable()
00550 {
00551     if(io == NULL) {
00552         printf("[WARNING] MTSBufferedIO not set\r\n");
00553         return 0;
00554     }
00555     if(!socketOpened) {
00556         printf("[WARNING] Socket is not open\r\n");
00557         return 0;
00558     }
00559 
00560     return io->writeable();
00561 }
00562 
00563 void Cellular::reset()
00564 {
00565     disconnect();
00566     Code code = sendBasicCommand("AT#RESET=0", 10000);
00567     if(code != MTS_SUCCESS) {
00568         printf("[ERROR] Socket Modem did not accept RESET command\n\r");
00569     } else {
00570         printf("[WARNING] Socket Modem is resetting, allow 30 seconds for it to come back\n\r");
00571     }
00572 }
00573 
00574 std::string Cellular::getDeviceIP()
00575 {
00576     return local_address;
00577 }
00578 
00579 Code Cellular::test()
00580 {
00581     int i = 0;
00582     while (sendBasicCommand("AT", 1000) != MTS_SUCCESS) {
00583         i++;
00584         if (i >= 30) {
00585             printf("[ERROR] Could not talk to radio after 30 tries\r\n");
00586             i = 0;
00587         }
00588         wait(1);
00589     }
00590     return MTS_SUCCESS;
00591 }
00592 
00593 Code Cellular::echo(bool state)
00594 {
00595     Code code;
00596     if (state) {
00597         code = sendBasicCommand("ATE0", 1000);
00598         echoMode = (code == MTS_SUCCESS) ? false : echoMode;
00599     } else {
00600         code = sendBasicCommand("ATE1", 1000);
00601         echoMode = (code == MTS_SUCCESS) ? true : echoMode;
00602     }
00603     return code;
00604 }
00605 
00606 int Cellular::getSignalStrength()
00607 {
00608     string response = sendCommand("AT+CSQ", 1000);
00609     if (response.find("OK") == string::npos) {
00610         return -1;
00611     }
00612     int start = response.find(':');
00613     int stop = response.find(',', start);
00614     string signal = response.substr(start + 2, stop - start - 2);
00615     int value;
00616     sscanf(signal.c_str(), "%d", &value);
00617     return value;
00618 }
00619 
00620 Cellular::Registration Cellular::getRegistration()
00621 {
00622     string response = sendCommand("AT+CREG?", 5000);
00623     if (response.find("OK") == string::npos) {
00624         return UNKNOWN;
00625     }
00626     int start = response.find(',');
00627     int stop = response.find(' ', start);
00628     string regStat = response.substr(start + 1, stop - start - 1);
00629     int value;
00630     sscanf(regStat.c_str(), "%d", &value);
00631     switch (value) {
00632         case 0:
00633             return NOT_REGISTERED;
00634         case 1:
00635             return REGISTERED;
00636         case 2:
00637             return SEARCHING;
00638         case 3:
00639             return DENIED;
00640         case 4:
00641             return UNKNOWN;
00642         case 5:
00643             return ROAMING;
00644     }
00645     return UNKNOWN;
00646 }
00647 
00648 Code Cellular::setApn(const std::string& apn)
00649 {
00650     Code code = sendBasicCommand("AT#APNSERV=\"" + apn + "\"", 1000);
00651     if (code != MTS_SUCCESS) {
00652         return code;
00653     }
00654     this->apn = apn;
00655     return code;
00656 }
00657 
00658 
00659 Code Cellular::setDns(const std::string& primary, const std::string& secondary)
00660 {
00661     return sendBasicCommand("AT#DNS=1," + primary + "," + secondary, 1000);
00662 }
00663 
00664 bool Cellular::ping(const std::string& address)
00665 {
00666     char buffer[256] = {0};
00667     Code code;
00668 
00669     code = sendBasicCommand("AT#PINGREMOTE=\"" + address + "\"", 1000);
00670     if (code != MTS_SUCCESS) {
00671         return false;
00672     }
00673 
00674     sprintf(buffer, "AT#PINGNUM=%d", 1);
00675     code = sendBasicCommand(buffer , 1000);
00676     if (code != MTS_SUCCESS) {
00677         return false;
00678     }
00679 
00680     sprintf(buffer, "AT#PINGDELAY=%d", PINGDELAY);
00681     code = sendBasicCommand(buffer , 1000);
00682     if (code != MTS_SUCCESS) {
00683         return false;
00684     }
00685 
00686     std::string response;
00687     for (int i = 0; i < PINGNUM; i++) {
00688         response = sendCommand("AT#PING", PINGDELAY * 1000);
00689         if (response.find("alive") != std::string::npos) {
00690             return true;
00691         }
00692     }
00693     return false;
00694 }
00695 
00696 Code Cellular::setSocketCloseable(bool enabled)
00697 {
00698     if(socketCloseable == enabled) {
00699         return MTS_SUCCESS;
00700     }
00701 
00702     if(socketOpened) {
00703         printf("[ERROR] socket is already opened. Can not set closeable\r\n");
00704         return MTS_ERROR;
00705     }
00706 
00707     socketCloseable = enabled;
00708 
00709     return MTS_SUCCESS;
00710 }
00711 
00712 Code Cellular::sendSMS(const Sms& sms)
00713 {
00714     return sendSMS(sms.phoneNumber, sms.message);
00715 }
00716 
00717 Code Cellular::sendSMS(const std::string& phoneNumber, const std::string& message)
00718 {
00719     Code code = sendBasicCommand("AT+CMGF=1", 1000);
00720     if (code != MTS_SUCCESS) {
00721         return code;
00722     }
00723     string cmd = "AT+CMGS=\"+";
00724     cmd.append(phoneNumber);
00725     cmd.append("\"");
00726     string response1 = sendCommand(cmd, 1000);
00727     if (response1.find('>') == string::npos) {
00728         return MTS_NO_RESPONSE;
00729     }
00730     wait(.2);
00731     string  response2 = sendCommand(message, 4000, CTRL_Z);
00732     printf("SMS Response: %s\r\n", response2.c_str());
00733     if (response2.find("+CMGS:") == string::npos) {
00734         return MTS_FAILURE;
00735     }
00736     return MTS_SUCCESS;
00737 }
00738 
00739 std::vector<Cellular::Sms> Cellular::getReceivedSms()
00740 {
00741     int smsNumber = 0;
00742     std::vector<Sms> vSms;
00743     std::string received = sendCommand("AT+CMGL=\"ALL\"", 4000);
00744     size_t pos = received.find("+CMGL: ");
00745 
00746     while (pos != std::string::npos) {
00747         Cellular::Sms sms;
00748         std::string line(Text::getLine(received, pos, pos));
00749         //printf("[DEBUG] Top of SMS Parse Loop. LINE[%s]\r\n", line.c_str());
00750         if(line.find("+CMGL: ") == std::string::npos) {
00751             continue;
00752         }
00753 
00754         //Start of SMS message
00755         std::vector<std::string> vSmsParts = Text::split(line, ',');
00756         if(vSmsParts.size() != 6) {
00757             printf("[WARNING] Expected 6 commas. SMS[%d] DATA[%s]. Continuing ...\r\n", smsNumber, line.c_str());
00758             continue;
00759         }
00760 
00761         sms.phoneNumber = vSmsParts[2];
00762         sms.timestamp = vSmsParts[4] + ", " + vSmsParts[5];
00763 
00764         if(pos == std::string::npos) {
00765             printf("[WARNING] Expected SMS body. SMS[%d]. Leaving ...\r\n", smsNumber);
00766             break;
00767         }
00768         //Check for the start of the next SMS message
00769         size_t bodyEnd = received.find("\r\n+CMGL: ", pos);
00770         if(bodyEnd == std::string::npos) {
00771             //printf("[DEBUG] Parsing Last SMS. SMS[%d]\r\n", smsNumber);
00772             //This must be the last SMS message
00773             bodyEnd = received.find("\r\n\r\nOK", pos);
00774         }
00775 
00776         //Safety check that we found the boundary of this current SMS message
00777         if(bodyEnd != std::string::npos) {
00778             sms.message = received.substr(pos, bodyEnd - pos);
00779         } else {
00780             sms.message = received.substr(pos);
00781             printf("[WARNING] Expected to find end of SMS list. SMS[%d] DATA[%s].\r\n", smsNumber, sms.message.c_str());
00782         }
00783         vSms.push_back(sms);
00784         pos = bodyEnd;
00785         //printf("[DEBUG] Parsed SMS[%d].  Starting Next at position [%d]\r\n", smsNumber, pos);
00786         smsNumber++;
00787     }
00788     printf("Received %d SMS\r\n", smsNumber);
00789     return vSms;
00790 }
00791 
00792 Code Cellular::deleteOnlyReceivedReadSms()
00793 {
00794     return sendBasicCommand("AT+CMGD=1,1", 1000);
00795 }
00796 
00797 Code Cellular::deleteAllReceivedSms()
00798 {
00799     return sendBasicCommand("AT+CMGD=1,4", 1000);
00800 }
00801 
00802 Code Cellular::sendBasicCommand(const std::string& command, unsigned int timeoutMillis, char esc)
00803 {
00804     if(socketOpened) {
00805         printf("[ERROR] socket is open. Can not send AT commands\r\n");
00806         return MTS_ERROR;
00807     }
00808 
00809     string response = sendCommand(command, timeoutMillis, esc);
00810     if (response.size() == 0) {
00811         return MTS_NO_RESPONSE;
00812     } else if (response.find("OK") != string::npos) {
00813         return MTS_SUCCESS;
00814     } else if (response.find("ERROR") != string::npos) {
00815         return MTS_ERROR;
00816     } else {
00817         return MTS_FAILURE;
00818     }
00819 }
00820 
00821 string Cellular::sendCommand(const std::string& command, unsigned int timeoutMillis, char esc)
00822 {
00823     if(io == NULL) {
00824         printf("[ERROR] MTSBufferedIO not set\r\n");
00825         return "";
00826     }
00827     if(socketOpened) {
00828         printf("[ERROR] socket is open. Can not send AT commands\r\n");
00829         return "";
00830     }
00831 
00832     io->rxClear();
00833     io->txClear();
00834     std::string result;
00835 
00836     //Attempt to write command
00837     if(io->write(command.data(), command.size(), timeoutMillis) != command.size()) {
00838         //Failed to write command
00839         if (command != "AT" && command != "at") {
00840             printf("[ERROR] failed to send command to radio within %d milliseconds\r\n", timeoutMillis);
00841         }
00842         return "";
00843     }
00844 
00845     //Send Escape Character
00846     if (esc != 0x00) {
00847         if(io->write(esc, timeoutMillis) != 1) {
00848             if (command != "AT" && command != "at") {
00849                 printf("[ERROR] failed to send character '%c' (0x%02X) to radio within %d milliseconds\r\n", esc, esc, timeoutMillis);
00850             }
00851             return "";
00852         }
00853     }
00854 
00855     int timer = 0;
00856     size_t previous = 0;
00857     char tmp[256];
00858     tmp[255] = 0;
00859     bool started = !echoMode;
00860     bool done = false;
00861     do {
00862         wait(0.1);
00863         timer += 100;
00864 
00865         previous = result.size();
00866         //Make a non-blocking read call by passing timeout of zero
00867         int size = io->read(tmp,255,0);    //1 less than allocated (timeout is instant)
00868         if(size > 0) {
00869             result.append(tmp, size);
00870         }
00871         if(!started) {
00872             //In Echo Mode (Command will have echo'd + 2 characters for \r\n)
00873             if(result.size() > command.size() + 2) {
00874                 started = true;
00875             }
00876         } else {
00877             done =  (result.size() == previous);
00878         }
00879         if(timer >= timeoutMillis) {
00880             if (command != "AT" && command != "at") {
00881                 printf("[WARNING] sendCommand [%s] timed out after %d milliseconds\r\n", command.c_str(), timeoutMillis);
00882             }
00883             done = true;
00884         }
00885     } while (!done);
00886 
00887     return result;
00888 }
00889 
00890 std::string Cellular::getRegistrationNames(Registration registration)
00891 {
00892     switch(registration) {
00893         case NOT_REGISTERED:
00894             return "NOT_REGISTERED";
00895         case REGISTERED:
00896             return "REGISTERED";
00897         case SEARCHING:
00898             return "SEARCHING";
00899         case DENIED:
00900             return "DENIED";
00901         case UNKNOWN:
00902             return "UNKNOWN";
00903         case ROAMING:
00904             return "ROAMING";
00905         default:
00906             return "UNKNOWN ENUM";
00907     }
00908 }