Cellular library for MTS Socket Modem Arduino Shield devices from Multi-Tech Systems

Dependents:   mtsas mtsas mtsas mtsas

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers UIP.cpp Source File

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 }