Cellular library for MTS Socket Modem Arduino Shield devices from Multi-Tech Systems
Dependents: mtsas mtsas mtsas mtsas
UIP.cpp
00001 #include "mbed.h" 00002 #include "UIP.h" 00003 #include "MTSText.h" 00004 #include "MTSLog.h" 00005 #include "CellUtils.h" 00006 00007 using namespace mts; 00008 00009 UIP::UIP(Radio type) 00010 { 00011 this->type = type; 00012 io = NULL; 00013 dcd = NULL; 00014 dtr = NULL; 00015 resetLine = NULL; 00016 echoMode = true; 00017 pppConnected = false; 00018 socketMode = TCP; 00019 socketOpened = false; 00020 socketCloseable = true; 00021 local_port = 0; 00022 local_address = ""; 00023 host_port = 0; 00024 } 00025 00026 UIP::~UIP() 00027 { 00028 if (dtr != NULL) { 00029 dtr->write(1); 00030 } 00031 00032 delete dcd; 00033 delete dtr; 00034 delete resetLine; 00035 } 00036 00037 bool UIP::init(MTSBufferedIO* io) 00038 { 00039 if (! Cellular::init(io)) { 00040 return false; 00041 } 00042 00043 logDebug("radio type: %s", Cellular::getRadioNames(type).c_str()); 00044 return true; 00045 } 00046 00047 bool UIP::connect() 00048 { 00049 //Check if APN is not set, if it is not, connect will not work. 00050 if (type == MTSMC_H5_IP || type == MTSMC_H5 || type == MTSMC_G3) { 00051 if(apn.size() == 0) { 00052 logDebug("APN is not set"); 00053 return false; 00054 } 00055 } 00056 00057 //Check if socket is open 00058 if(socketOpened) { 00059 return true; 00060 } 00061 00062 //Check if already connected 00063 if(isConnected()) { 00064 return true; 00065 } 00066 00067 Timer tmr; 00068 00069 //Check Registration: AT+CREG? == 0,1 00070 tmr.start(); 00071 do { 00072 Registration registration = getRegistration(); 00073 if(registration != REGISTERED) { 00074 logTrace("Not Registered [%d] ... waiting", (int)registration); 00075 wait(1); 00076 } else { 00077 break; 00078 } 00079 } while(tmr.read() < 30); 00080 00081 //Check RSSI: AT+CSQ 00082 tmr.reset(); 00083 do { 00084 int rssi = getSignalStrength(); 00085 logDebug("Signal strength: %d", rssi); 00086 if(rssi == 99 || rssi == -1) { 00087 logTrace("No Signal ... waiting"); 00088 wait(1); 00089 } else { 00090 break; 00091 } 00092 } while(tmr.read() < 30); 00093 00094 //AT#CONNECTIONSTART: Make a PPP connection 00095 if (type == MTSMC_H5_IP) { 00096 logDebug("Making PPP Connection Attempt. APN[%s]", apn.c_str()); 00097 } else { 00098 logDebug("Making PPP Connection Attempt"); 00099 } 00100 std::string pppResult = sendCommand("AT#CONNECTIONSTART", 120000); 00101 00102 if(pppResult.find("Ok_Info_GprsActivation") != std::string::npos) { 00103 std::vector<std::string> parts = Text::split(pppResult, "\r\n"); 00104 if(parts.size() >= 2) { 00105 local_address = parts[1]; 00106 } 00107 logInfo("PPP Connection Established: IP[%s]", local_address.c_str()); 00108 pppConnected = true; 00109 00110 } else { 00111 pppConnected = false; 00112 } 00113 00114 return pppConnected; 00115 } 00116 00117 void UIP::disconnect() 00118 { 00119 //AT#CONNECTIONSTOP: Close a PPP connection 00120 logDebug("Closing PPP Connection"); 00121 00122 if(socketOpened) { 00123 close(true); 00124 } 00125 00126 Code code = sendBasicCommand("AT#CONNECTIONSTOP", 10000); 00127 if(code == MTS_SUCCESS) { 00128 logDebug("Successfully closed PPP Connection"); 00129 } else { 00130 logError("Closing PPP Connection [%d]. Continuing ...", (int)code); 00131 } 00132 00133 pppConnected = false; 00134 } 00135 00136 bool UIP::isConnected() 00137 { 00138 //1) Check if APN was set if we're on an HSPA radio 00139 if (type == MTSMC_H5_IP || type == MTSMC_H5 || type == MTSMC_G3) { 00140 if(apn.size() == 0) { 00141 logDebug("APN is not set"); 00142 return false; 00143 } 00144 } 00145 00146 //2) Check that we do not have a live connection up 00147 if(socketOpened) { 00148 logDebug("Socket is opened"); 00149 return true; 00150 } 00151 //3) Query the radio 00152 std::string result = sendCommand("AT#VSTATE", 3000); 00153 if(result.find("CONNECTED") != std::string::npos) { 00154 if(pppConnected == false) { 00155 logWarning("Internal PPP state tracking differs from radio (DISCONNECTED:CONNECTED)"); 00156 } 00157 pppConnected = true; 00158 } else { 00159 if(pppConnected == true) { 00160 //Find out what state is 00161 size_t pos = result.find("STATE:"); 00162 if(pos != std::string::npos) { 00163 result = Text::getLine(result, pos + sizeof("STATE:"), pos); 00164 logWarning("Internal PPP state tracking differs from radio (CONNECTED:%s)", result.c_str()); 00165 } else { 00166 logError("Unable to parse radio state: [%s]", result.c_str()); 00167 } 00168 00169 } 00170 pppConnected = false; 00171 } 00172 00173 return pppConnected; 00174 } 00175 00176 bool UIP::open(const std::string& address, unsigned int port, Mode mode) 00177 { 00178 char buffer[256] = {0}; 00179 Code portCode, addressCode; 00180 00181 //1) Check that we do not have a live connection up 00182 if(socketOpened) { 00183 //Check that the address, port, and mode match 00184 if(host_address != address || host_port != port || socketMode != mode) { 00185 if(socketMode == TCP) { 00186 logError("TCP socket already opened [%s:%d]", host_address.c_str(), host_port); 00187 } else { 00188 logError("UDP socket already opened [%s:%d]", host_address.c_str(), host_port); 00189 } 00190 return false; 00191 } 00192 00193 logDebug("Socket already opened"); 00194 return true; 00195 } 00196 00197 //2) Check Parameters 00198 if(port > 65535) { 00199 logError("port out of range (0-65535)"); 00200 return false; 00201 } 00202 00203 //3) Check PPP connection 00204 if(!isConnected()) { 00205 logError("PPP not established. Attempting to connect"); 00206 if(!connect()) { 00207 logError("PPP connection failed"); 00208 return false; 00209 } else { 00210 logDebug("PPP connection established"); 00211 } 00212 } 00213 00214 //Set Local Port 00215 if(local_port != 0) { 00216 //Attempt to set local port 00217 sprintf(buffer, "AT#OUTPORT=%d", local_port); 00218 Code code = sendBasicCommand(buffer, 1000); 00219 if(code != MTS_SUCCESS) { 00220 logWarning("Unable to set local port (%d) [%d]", local_port, (int) code); 00221 } 00222 } 00223 00224 //Set TCP/UDP parameters 00225 if(mode == TCP) { 00226 if(socketCloseable) { 00227 Code code = sendBasicCommand("AT#DLEMODE=1,1", 1000); 00228 if(code != MTS_SUCCESS) { 00229 logWarning("Unable to set socket closeable [%d]", (int) code); 00230 } 00231 } 00232 sprintf(buffer, "AT#TCPPORT=1,%d", port); 00233 portCode = sendBasicCommand(buffer, 1000); 00234 addressCode = sendBasicCommand("AT#TCPSERV=1,\"" + address + "\"", 1000); 00235 } else { 00236 if(socketCloseable) { 00237 Code code = sendBasicCommand("AT#UDPDLEMODE=1", 1000); 00238 if(code != MTS_SUCCESS) { 00239 logWarning("Unable to set socket closeable [%d]", (int) code); 00240 } 00241 } 00242 sprintf(buffer, "AT#UDPPORT=%d", port); 00243 portCode = sendBasicCommand(buffer, 1000); 00244 addressCode = sendBasicCommand("AT#UDPSERV=\"" + address + "\"", 1000); 00245 } 00246 00247 if(portCode == MTS_SUCCESS) { 00248 host_port = port; 00249 } else { 00250 logError("Host port could not be set"); 00251 } 00252 00253 if(addressCode == MTS_SUCCESS) { 00254 host_address = address; 00255 } else { 00256 logError("Host address could not be set"); 00257 } 00258 00259 // Try and Connect 00260 std::string sMode; 00261 std::string sOpenSocketCmd; 00262 if(mode == TCP) { 00263 sOpenSocketCmd = "AT#OTCP=1"; 00264 sMode = "TCP"; 00265 } else { 00266 sOpenSocketCmd = "AT#OUDP"; 00267 sMode = "UDP"; 00268 } 00269 00270 string response = sendCommand(sOpenSocketCmd, 30000); 00271 if (response.find("Ok_Info_WaitingForData") != string::npos) { 00272 logInfo("Opened %s Socket [%s:%d]", sMode.c_str(), address.c_str(), port); 00273 socketOpened = true; 00274 socketMode = mode; 00275 } else { 00276 logWarning("Unable to open %s Socket [%s:%d]", sMode.c_str(), address.c_str(), port); 00277 socketOpened = false; 00278 } 00279 00280 return socketOpened; 00281 } 00282 00283 bool UIP::close(bool shutdown) 00284 { 00285 if(io == NULL) { 00286 logError("MTSBufferedIO not set"); 00287 return false; 00288 } 00289 00290 if(!socketOpened) { 00291 logWarning("Socket close() called, but socket was not open"); 00292 return true; 00293 } 00294 00295 if(!socketCloseable) { 00296 logError("Socket is not closeable"); 00297 return false; 00298 } 00299 00300 if(io->write(ETX, 1000) != 1) { 00301 logError("Timed out attempting to close socket"); 00302 return false; 00303 } 00304 00305 if (shutdown) { 00306 int counter = 0; 00307 char tmp[256]; 00308 do { 00309 if(socketOpened == false) { 00310 break; 00311 } 00312 read(tmp, 256, 1000); 00313 } while(counter++ < 10); 00314 00315 io->rxClear(); 00316 io->txClear(); 00317 } 00318 00319 socketOpened = false; 00320 return true; 00321 } 00322 00323 int UIP::read(char* data, int max, int timeout) 00324 { 00325 if(io == NULL) { 00326 logError("MTSBufferedIO not set"); 00327 return -1; 00328 } 00329 00330 //Check that nothing is in the rx buffer 00331 if(!socketOpened && !io->readable()) { 00332 logError("Socket is not open"); 00333 return -1; 00334 } 00335 00336 int bytesRead = 0; 00337 00338 if(timeout >= 0) { 00339 bytesRead = io->read(data, max, static_cast<unsigned int>(timeout)); 00340 } else { 00341 bytesRead = io->read(data, max); 00342 } 00343 00344 if(bytesRead > 0 && socketCloseable) { 00345 //Remove escape characters 00346 int index = 0; 00347 bool escapeFlag = false; 00348 for(int i = 0; i < bytesRead; i++) { 00349 if(data[i] == DLE || data[i] == ETX) { 00350 if(escapeFlag == true) { 00351 //This character has been escaped 00352 escapeFlag = false; 00353 } else if(data[bytesRead] == DLE) { 00354 //Found escape character 00355 escapeFlag = true; 00356 continue; 00357 } else { 00358 //ETX sent without escape -> Socket closed 00359 logInfo("Read ETX character without DLE escape. Socket closed"); 00360 socketOpened = false; 00361 continue; 00362 } 00363 } 00364 00365 if(index != i) { 00366 data[index] = data[i]; 00367 } 00368 index++; 00369 } 00370 bytesRead = index; 00371 } 00372 00373 //Scan for socket closed message 00374 for(size_t i = 0; i < bytesRead; i++) { 00375 if(data[i] == 'O') { 00376 if(strstr(&data[i], "Ok_Info_SocketClosed")) { 00377 logInfo("Found socket closed message. Socket closed"); 00378 //Close socket and Cut Off End of Message 00379 socketOpened = false; 00380 data[i] = '\0'; 00381 bytesRead = i; 00382 break; 00383 } 00384 } 00385 } 00386 return bytesRead; 00387 } 00388 00389 int UIP::write(const char* data, int length, int timeout) 00390 { 00391 if(io == NULL) { 00392 logError("MTSBufferedIO not set"); 00393 return -1; 00394 } 00395 00396 if(!socketOpened) { 00397 logError("Socket is not open"); 00398 return -1; 00399 } 00400 00401 //In order to avoid allocating another buffer, capture indices of 00402 //characters to escape during write 00403 int specialWritten = 0; 00404 std::vector<int> vSpecial; 00405 if(socketCloseable) { 00406 for(int i = 0; i < length; i++) { 00407 if(data[i] == ETX || data[i] == DLE) { 00408 //Push back index of special characters 00409 vSpecial.push_back(i); 00410 } 00411 } 00412 } 00413 00414 int bytesWritten = 0; 00415 if(timeout >= 0) { 00416 Timer tmr; 00417 tmr.start(); 00418 do { 00419 int available = io->writeable(); 00420 if (available > 0) { 00421 if(specialWritten < vSpecial.size()) { 00422 //Check if current index is at a special character 00423 if(bytesWritten == vSpecial[specialWritten]) { 00424 if(available < 2) { 00425 //Requires at least two bytes of space 00426 wait(0.05); 00427 continue; 00428 } 00429 //Ready to write special character 00430 if(io->write(DLE)) { 00431 specialWritten++; 00432 if(io->write(data[bytesWritten])) { 00433 bytesWritten++; 00434 } 00435 } else { 00436 //Unable to write escape character, try again next round 00437 wait(0.05); 00438 } 00439 } else { 00440 //We want to write all the way up to the next special character 00441 int relativeIndex = vSpecial[specialWritten] - bytesWritten; 00442 int size = mts_min(available, relativeIndex); 00443 bytesWritten += io->write(&data[bytesWritten], size); 00444 } 00445 } else { 00446 int size = mts_min(available, length - bytesWritten); 00447 bytesWritten += io->write(&data[bytesWritten], size); 00448 } 00449 } else { 00450 wait(0.05); 00451 } 00452 } while (tmr.read_ms() <= timeout && bytesWritten < length); 00453 } else { 00454 for(int i = 0; i < vSpecial.size(); i++) { 00455 //Write up to the special character, then write the special character 00456 int size = vSpecial[i] - bytesWritten; 00457 int currentWritten = io->write(&data[bytesWritten], size); 00458 bytesWritten += currentWritten; 00459 if(currentWritten != size) { 00460 //Failed to write up to the special character. 00461 return bytesWritten; 00462 } 00463 if(io->write(DLE) && io->write(data[bytesWritten])) { 00464 bytesWritten++; 00465 } else { 00466 //Failed to write the special character. 00467 return bytesWritten; 00468 } 00469 } 00470 00471 bytesWritten = io->write(&data[bytesWritten], length - bytesWritten); 00472 } 00473 00474 return bytesWritten; 00475 } 00476 00477 Code UIP::setApn(const std::string& apn) 00478 { 00479 if (type == MTSMC_H5_IP) { 00480 Code code = sendBasicCommand("AT#APNSERV=\"" + apn + "\"", 1000); 00481 if (code != MTS_SUCCESS) { 00482 return code; 00483 } 00484 this->apn = apn; 00485 return code; //This will return MTS_SUCCESS 00486 } else { 00487 logInfo("CDMA radios don't need an APN"); 00488 return MTS_SUCCESS; 00489 } 00490 } 00491 00492 void UIP::reset() 00493 { 00494 disconnect(); 00495 Code code = sendBasicCommand("AT#RESET=0", 10000); 00496 if(code != MTS_SUCCESS) { 00497 logError("Socket Modem did not accept RESET command\n\r"); 00498 } else { 00499 logWarning("Socket Modem is resetting, allow 30 seconds for it to come back\n\r"); 00500 } 00501 } 00502 00503 bool UIP::ping(const std::string& address) 00504 { 00505 char buffer[256] = {0}; 00506 Code code; 00507 00508 code = sendBasicCommand("AT#PINGREMOTE=\"" + address + "\"", 1000); 00509 if (code != MTS_SUCCESS) { 00510 return false; 00511 } 00512 00513 sprintf(buffer, "AT#PINGNUM=%d", 1); 00514 code = sendBasicCommand(buffer , 1000); 00515 if (code != MTS_SUCCESS) { 00516 return false; 00517 } 00518 00519 sprintf(buffer, "AT#PINGDELAY=%d", PINGDELAY); 00520 code = sendBasicCommand(buffer , 1000); 00521 if (code != MTS_SUCCESS) { 00522 return false; 00523 } 00524 00525 std::string response; 00526 for (int i = 0; i < PINGNUM; i++) { 00527 response = sendCommand("AT#PING", PINGDELAY * 2000); 00528 if (response.find("alive") != std::string::npos) { 00529 /* the "OK" that comes on a new line doesn't come right after this reply 00530 * wait a couple seconds to make sure we get it here, otherwise it could be read 00531 * as the response to the next AT command sent 00532 */ 00533 wait(2); 00534 return true; 00535 } 00536 } 00537 return false; 00538 }
Generated on Tue Jul 12 2022 21:59:41 by 1.7.2