Peter Ferland / MTS-Cellular-ME910

Fork of MTS-Cellular by MultiTech

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