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 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 }
Generated on Wed Jul 13 2022 08:05:41 by
1.7.2
