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

Dependents:   mtsas mtsas mtsas mtsas

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Cellular.cpp Source File

Cellular.cpp

00001 #include "mbed.h"
00002 #include "Cellular.h"
00003 #include "MTSText.h"
00004 #include "MTSLog.h"
00005 
00006 using namespace mts;
00007 
00008 bool Cellular::init(MTSBufferedIO* io)
00009 {
00010     if (io == NULL) {
00011         return false;
00012     }
00013     this->io = io;
00014 
00015     return true;
00016 }
00017 
00018 bool Cellular::configureSignals(unsigned int DCD, unsigned int DTR, unsigned int RESET)
00019 {
00020     //Set DCD - The radio will raise and lower this line
00021     if (DCD != NC) {
00022         dcd = new DigitalIn(PinName(DCD));
00023     }
00024     /* Set DTR - This line should be lowered when we want to talk to the radio and raised when we're done
00025     * for now we will lower it in the constructor and raise it in the destructor.
00026     */
00027     if (DTR != NC) {
00028         dtr = new DigitalOut(PinName(DTR));
00029         dtr->write(0);
00030     }
00031     //Set RESET - Set the hardware reset line to the radio
00032     if (RESET != NC) {
00033         resetLine = new DigitalOut(PinName(RESET));
00034     }
00035     return true;
00036 }
00037 
00038 std::string Cellular::getRegistrationNames(Registration registration)
00039 {
00040     switch(registration) {
00041         case NOT_REGISTERED:
00042             return "NOT_REGISTERED";
00043         case REGISTERED:
00044             return "REGISTERED";
00045         case SEARCHING:
00046             return "SEARCHING";
00047         case DENIED:
00048             return "DENIED";
00049         case UNKNOWN:
00050             return "UNKNOWN";
00051         case ROAMING:
00052             return "ROAMING";
00053         default:
00054             return "UNKNOWN ENUM";
00055     }
00056 }
00057 
00058 std::string Cellular::getRadioNames(Radio radio) {
00059     switch(radio) {
00060         case MTSMC_H5:
00061             return "MTSMC-H5";
00062         case MTSMC_EV3:
00063             return "MTSMC-EV3";
00064         case MTSMC_G3:
00065             return "MTSMC-G3";
00066         case MTSMC_C2:
00067             return "MTSMC-C2";
00068         case MTSMC_H5_IP:
00069             return "MTSMC-H5-IP";
00070         case MTSMC_EV3_IP:
00071             return "MTSMC-EV3-IP";
00072         case MTSMC_C2_IP:
00073             return "MTSMC-C2-IP";
00074         case MTSMC_LAT1:
00075             return "MTSMC_LAT1";
00076         case MTSMC_LEU1:
00077             return "MTSMC_LEU1";
00078         case MTSMC_LVW2:
00079             return "MTSMC_LVW2";
00080         case MTQ_LAT3:
00081             return "MTQ_LAT3";
00082         case MTQ_LVW3:
00083             return "MTQ_LVW3";            
00084         case MTQ_MAT1:
00085             return "MTQ-MAT1";
00086         case MTQ_MVW1:
00087             return "MTQ-MVW1";
00088         default:
00089             return "UNKNOWN ENUM";
00090     }
00091 }
00092 
00093 Code Cellular::test()
00094 {
00095     int i = 0;
00096     while (sendBasicCommand("AT", 1000) != MTS_SUCCESS) {
00097         i++;
00098         if (i >= 30) {
00099             logError("Could not talk to radio after 30 tries");
00100             i = 0;
00101         }
00102         wait(1);
00103     }
00104     return MTS_SUCCESS;
00105 }
00106 
00107 int Cellular::getSignalStrength()
00108 {
00109     string response = sendCommand("AT+CSQ", 1000);
00110     if (response.find("OK") == string::npos) {
00111         return -1;
00112     }
00113     int start = response.find(':');
00114     int stop = response.find(',', start);
00115     string signal = response.substr(start + 2, stop - start - 2);
00116     int value;
00117     sscanf(signal.c_str(), "%d", &value);
00118     return value;
00119 }
00120 
00121 Cellular::Registration Cellular::getRegistration()
00122 {
00123     if (type == MTQ_LVW3) 
00124         string response = sendCommand("AT+CEREG?", 5000);
00125     else
00126         string response = sendCommand("AT+CREG?", 5000);
00127     if (response.find("OK") == string::npos) {
00128         return UNKNOWN;
00129     }
00130     int start = response.find(',');
00131     int stop = response.find(' ', start);
00132     string regStat = response.substr(start + 1, stop - start - 1);
00133     int value;
00134     sscanf(regStat.c_str(), "%d", &value);
00135     switch (value) {
00136         case 0:
00137             return NOT_REGISTERED;
00138         case 1:
00139             return REGISTERED;
00140         case 2:
00141             return SEARCHING;
00142         case 3:
00143             return DENIED;
00144         case 4:
00145             return UNKNOWN;
00146         case 5:
00147             return ROAMING;
00148     }
00149     return UNKNOWN;
00150 }
00151 
00152 Code Cellular::setDns(const std::string& primary, const std::string& secondary)
00153 {
00154     return sendBasicCommand("AT#DNS=1," + primary + "," + secondary, 1000);
00155 }
00156 
00157 Code Cellular::sendSMS(const Sms& sms)
00158 {
00159     return sendSMS(sms.phoneNumber, sms.message);
00160 }
00161 
00162 Code Cellular::sendBasicCommand(const std::string& command, unsigned int timeoutMillis, char esc)
00163 {
00164     if(socketOpened) {
00165         logError("socket is open. Can not send AT commands");
00166         return MTS_ERROR;
00167     }
00168 
00169     string response = sendCommand(command, timeoutMillis, esc);
00170     if (response.size() == 0) {
00171         return MTS_NO_RESPONSE;
00172     } else if (response.find("OK") != string::npos) {
00173         return MTS_SUCCESS;
00174     } else if (response.find("ERROR") != string::npos) {
00175         return MTS_ERROR;
00176     } else {
00177         return MTS_FAILURE;
00178     }
00179 }
00180 
00181 string Cellular::sendCommand(const std::string& command, unsigned int timeoutMillis, char esc)
00182 {
00183     if(io == NULL) {
00184         logError("MTSBufferedIO not set");
00185         return "";
00186     }
00187     if(socketOpened) {
00188         logError("socket is open. Can not send AT commands");
00189         return "";
00190     }
00191 
00192     io->rxClear();
00193     io->txClear();
00194     std::string result;
00195 
00196     //Attempt to write command
00197     if(io->write(command.data(), command.size(), timeoutMillis) != command.size()) {
00198         //Failed to write command
00199         if (command != "AT" && command != "at") {
00200             logError("failed to send command to radio within %d milliseconds", timeoutMillis);
00201         }
00202         return "";
00203     }
00204 
00205     //Send Escape Character
00206     if (esc != 0x00) {
00207         if(io->write(esc, timeoutMillis) != 1) {
00208             if (command != "AT" && command != "at") {
00209                 logError("failed to send character '%c' (0x%02X) to radio within %d milliseconds", esc, esc, timeoutMillis);
00210             }
00211             return "";
00212         }
00213     }
00214     mbed::Timer tmr;
00215     char tmp[256];
00216     tmp[255] = 0;
00217     bool done = false;
00218     tmr.start();
00219     do {
00220         //Make a non-blocking read call by passing timeout of zero
00221         int size = io->read(tmp,255,0);    //1 less than allocated (timeout is instant)
00222         if(size > 0) {
00223             result.append(tmp, size);
00224         }
00225         
00226         //Check for a response to signify the completion of the AT command
00227         //OK, ERROR, CONNECT are the 3 most likely responses
00228         if(result.size() > (command.size() + 2)) {
00229                 if(result.find("OK\r\n",command.size()) != std::string::npos) {
00230                     done = true;
00231                 } else if (result.find("ERROR") != std::string::npos) {
00232                     done = true;
00233                 } else if (result.find("NO CARRIER\r\n") != std::string::npos) {
00234                     done = true;
00235                 }
00236                 
00237                 if(type == MTSMC_H5 || type == MTSMC_G3 || type == MTSMC_EV3 || type == MTSMC_C2 || type == MTSMC_LAT1 || type == MTSMC_LEU1 ||
00238                     type == MTSMC_LVW2 || type == MTQ_LAT3 || type == MTQ_LVW3 || type == MTQ_MAT1 || type == MTQ_MVW1) {
00239                     if (result.find("CONNECT\r\n") != std::string::npos) {
00240                         done = true;
00241                     } 
00242                 } else if (type == MTSMC_H5_IP || type == MTSMC_EV3_IP || type == MTSMC_C2_IP) {
00243                     if (result.find("Ok_Info_WaitingForData\r\n") != std::string::npos) {
00244                         done = true;
00245                     } else if (result.find("Ok_Info_SocketClosed\r\n") != std::string::npos) {
00246                         done = true;
00247                     } else if (result.find("Ok_Info_PPP\r\n") != std::string::npos) {
00248                         done = true;
00249                     } else if (result.find("Ok_Info_GprsActivation\r\n") != std::string::npos) {
00250                         done = true;
00251                     }
00252                 }
00253         }
00254         
00255         if(tmr.read_ms() >= timeoutMillis) {
00256             if (command != "AT" && command != "at") {
00257                 logWarning("sendCommand [%s] timed out after %d milliseconds", command.c_str(), timeoutMillis);
00258             }
00259             done = true;
00260         }
00261     } while (!done);
00262    
00263     return result;
00264 }
00265 
00266 Code Cellular::sendSMS(const std::string& phoneNumber, const std::string& message)
00267 {
00268     string csmp;
00269     
00270     if (type == MTSMC_H5_IP || type == MTSMC_H5 || type == MTSMC_G3 || type == MTSMC_LAT1 || type == MTSMC_LEU1 || 
00271         type == MTQ_LAT3 || type == MTQ_MAT1 || type == MTQ_MVW1) {
00272         csmp = "AT+CSMP=17,167,0,0";
00273     } else if (type == MTSMC_EV3_IP || type == MTSMC_EV3 || type == MTSMC_C2_IP || type == MTSMC_C2 || type == MTSMC_LVW2 ||
00274         type == MTQ_LVW3 ) {
00275         csmp = "AT+CSMP=,4098,0,2";
00276     } else {
00277         logError("unknown radio type [%d]", type);
00278         return MTS_FAILURE;
00279     }
00280     
00281     Code code = sendBasicCommand("AT+CMGF=1", 2000);
00282     if (code != MTS_SUCCESS) {
00283         logError("CMGF failed");
00284         return code;
00285     }
00286     
00287     code = sendBasicCommand(csmp, 1000);
00288     if (code != MTS_SUCCESS) {
00289         logError("CSMP failed [%s]", getRadioNames(type).c_str());
00290         return code;
00291     }
00292     
00293     string cmd = "AT+CMGS=\"";
00294     cmd.append("+");
00295     cmd.append(phoneNumber);
00296     cmd.append("\",145");
00297     for (int i = 0; i < 5; i++) {
00298         string response1 = sendCommand(cmd, 2000);
00299         if (response1.find('>') != string::npos) {
00300             break;
00301         }
00302         if (i >= 5) {
00303             logError("CMGS phone number failed");
00304             return MTS_NO_RESPONSE;
00305         }
00306         wait(1);
00307     }
00308     wait(.2);
00309     
00310     string  response2 = sendCommand(message, 15000, CTRL_Z);
00311     if (response2.find("+CMGS:") == string::npos) {
00312         logError("CMGS message failed");
00313         return MTS_FAILURE;
00314     }
00315         
00316     return MTS_SUCCESS;
00317 }
00318 
00319 std::vector<Cellular::Sms> Cellular::getReceivedSms()
00320 {
00321     int smsNumber = 0;
00322     std::vector<Sms> vSms;
00323     std::string received;
00324     size_t pos;
00325     
00326     Code code = sendBasicCommand("AT+CMGF=1", 2000);
00327     if (code != MTS_SUCCESS) {
00328         logError("CMGF failed");
00329         return vSms;
00330     }
00331     
00332     received = sendCommand("AT+CMGL=\"ALL\"", 5000);
00333     pos = received.find("+CMGL: ");
00334 
00335     while (pos != std::string::npos) {
00336         Cellular::Sms sms;
00337         std::string line(Text::getLine(received, pos, pos));
00338         if(line.find("+CMGL: ") == std::string::npos) {
00339             continue;
00340         }
00341         //Start of SMS message
00342         std::vector<std::string> vSmsParts = Text::split(line, ',');
00343         if (type == MTSMC_H5_IP || type == MTSMC_H5 || type == MTSMC_G3 || type == MTSMC_LAT1 || type == MTSMC_LEU1 || type == MTQ_LAT3 || type == MTQ_MAT1 || type == MTQ_MVW1) {
00344             /* format for H5 and H5-IP radios
00345              * <index>, <status>, <oa>, <alpha>, <scts>
00346              * scts contains a comma, so splitting on commas should give us 6 items
00347              */
00348             if(vSmsParts.size() != 6) {
00349                 logWarning("Expected 5 commas. SMS[%d] DATA[%s]. Continuing ...", smsNumber, line.c_str());
00350                 continue;
00351             }
00352 
00353             sms.phoneNumber = vSmsParts[2];
00354             sms.timestamp = vSmsParts[4] + ", " + vSmsParts[5];
00355         } else if (type == MTSMC_EV3_IP || type == MTSMC_EV3 || type == MTSMC_C2_IP || type == MTSMC_C2 || type == MTSMC_LVW2 || type == MTQ_LVW3) {
00356             /* format for EV3 and EV3-IP radios
00357              * <index>, <status>, <oa>, <callback>, <date>
00358              * splitting on commas should give us 5 items
00359              */
00360             if(vSmsParts.size() != 5) {
00361                 logWarning("Expected 4 commas. SMS[%d] DATA[%s]. Continuing ...", smsNumber, line.c_str());
00362                 continue;
00363             }
00364             
00365             sms.phoneNumber = vSmsParts[2];
00366             /* timestamp is in a nasty format
00367              * YYYYMMDDHHMMSS
00368              * nobody wants to try and decipher that, so format it nicely
00369              * YY/MM/DD,HH:MM:SS
00370              */
00371             string s = vSmsParts[4];
00372             if (type == MTSMC_LVW2) {
00373                 sms.timestamp = s.substr(3,2) + "/" + s.substr(5,2) + "/" + s.substr(7,2) + ", " + s.substr(9,2) + ":" + s.substr(11,2) + ":" + s.substr(13,2);
00374             } else {
00375                 sms.timestamp = s.substr(2,2) + "/" + s.substr(4,2) + "/" + s.substr(6,2) + ", " + s.substr(8,2) + ":" + s.substr(10,2) + ":" + s.substr(12,2);
00376             }
00377         }
00378 
00379         if(pos == std::string::npos) {
00380             logWarning("Expected SMS body. SMS[%d]. Leaving ...", smsNumber);
00381             break;
00382         }
00383         //Check for the start of the next SMS message
00384         size_t bodyEnd = received.find("\r\n+CMGL:", pos);
00385         if(bodyEnd == std::string::npos) {
00386             //This must be the last SMS message
00387             bodyEnd = received.find("\r\n\r\nOK", pos);
00388         }
00389         //Safety check that we found the boundary of this current SMS message
00390         if(bodyEnd != std::string::npos) {
00391             sms.message = received.substr(pos, bodyEnd - pos);
00392         } else {
00393             sms.message = received.substr(pos);
00394             logWarning("Expected to find end of SMS list. SMS[%d] DATA[%s].", smsNumber, sms.message.c_str());
00395         }
00396         vSms.push_back(sms);
00397         pos = bodyEnd;
00398         smsNumber++;
00399     }
00400     logInfo("Received %d SMS", smsNumber);
00401     return vSms;
00402 }
00403 
00404 Code Cellular::deleteOnlyReceivedReadSms()
00405 {
00406     return sendBasicCommand("AT+CMGD=1,1", 1000);
00407 }
00408 
00409 Code Cellular::deleteAllReceivedSms()
00410 {
00411     return sendBasicCommand("AT+CMGD=1,4", 1000);
00412 }
00413 
00414 unsigned int Cellular::readable()
00415 {
00416     if(io == NULL) {
00417         logWarning("MTSBufferedIO not set");
00418         return 0;
00419     }
00420     if(!socketOpened && !io->readable()) {
00421         logWarning("Socket is not open");
00422         return 0;
00423     }
00424     return io->readable();
00425 }
00426 
00427 std::string Cellular::getEquipmentIdentifier()
00428 {
00429     string equipmentIdentifier = sendCommand("AT+CGSN", 2000);
00430     std::vector<std::string> lines = Text::split(equipmentIdentifier, "\r\n");
00431     
00432     if (equipmentIdentifier.find("OK") != string::npos) {                
00433         equipmentIdentifier = lines[1];
00434     } else {
00435         //Empty string signifies failure
00436         equipmentIdentifier.clear();
00437     }
00438     
00439     return equipmentIdentifier;
00440 }
00441 
00442 int Cellular::getRadioType()
00443 {
00444     return type;
00445 }
00446 
00447 std::string Cellular::getRadioTypeString()
00448 {
00449     return getRadioNames(type);
00450 }
00451 
00452 unsigned int Cellular::writeable()
00453 {
00454     if(io == NULL) {
00455         logWarning("MTSBufferedIO not set");
00456         return 0;
00457     }
00458     if(!socketOpened) {
00459         logWarning("Socket is not open");
00460         return 0;
00461     }
00462 
00463     return io->writeable();
00464 }
00465 
00466 bool Cellular::setDeviceIP(std::string address)
00467 {
00468     if (address.compare("DHCP") == 0) {
00469         return true;
00470     } else {
00471         logWarning("Radio does not support static IPs, using DHCP.");
00472         return false;
00473     }
00474 }
00475 
00476 std::string Cellular::getDeviceIP()
00477 {
00478     return local_address;
00479 }
00480 
00481 //Turns off echo when it receives a true, turns on when it receives false
00482 Code Cellular::echo(bool state)
00483 {
00484     Code code;
00485     if (state) {
00486         code = sendBasicCommand("ATE0", 1000);
00487         echoMode = (code == MTS_SUCCESS) ? false : echoMode;
00488     } else {
00489         code = sendBasicCommand("ATE1", 1000);
00490         echoMode = (code == MTS_SUCCESS) ? true : echoMode;
00491     }
00492     return code;
00493 }
00494 
00495 //Pass 1 to enable socket closeable
00496 //Pass 0 to disable socket closeable
00497 Code Cellular::setSocketCloseable(bool enabled)
00498 {
00499     if(socketCloseable == enabled) {
00500         return MTS_SUCCESS;
00501     }
00502 
00503     if(socketOpened) {
00504         logError("socket is already opened. Can not set closeable");
00505         return MTS_ERROR;
00506     }
00507 
00508     socketCloseable = enabled;
00509 
00510     return MTS_SUCCESS;
00511 }
00512 
00513 bool Cellular::isOpen()
00514 {
00515     if(io->readable()) {
00516         logDebug("Assuming open, data available to read.");
00517         return true;
00518     }
00519     return socketOpened;
00520 }
00521 
00522 //Binds the socket to a specific port if able
00523 bool Cellular::bind(unsigned int port)
00524 {
00525     if(socketOpened) {
00526         logError("socket is open. Can not set local port");
00527         return false;
00528     }
00529     if(port > 65535) {
00530         logError("port out of range (0-65535)");
00531         return false;
00532     }
00533     local_port = port;
00534     return true;
00535 }
00536 
00537 bool Cellular::GPSenable(){
00538     return true;
00539 }
00540 
00541 bool Cellular::GPSdisable(){
00542     return true;
00543 }
00544 
00545 bool Cellular::GPSenabled(){
00546     return true;
00547 }
00548 Cellular::gpsData Cellular::GPSgetPosition(){
00549     gpsData response;
00550     response.success = true;
00551     return response;
00552 }
00553 
00554 bool Cellular::GPSgotFix(){
00555     return true;    
00556 }