Cellular library for MTS Socket Modem Arduino Shield devices from Multi-Tech Systems
Dependents: mtsas mtsas mtsas mtsas
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 }
Generated on Tue Jul 12 2022 21:59:41 by 1.7.2