Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of MTS-Cellular by
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 }
Generated on Tue Jul 12 2022 19:53:40 by
1.7.2
