Peter Ferland / MTS-Cellular_lat1

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