Peter Ferland / MTS-Cellular_lat1

Fork of MTS-Cellular by MultiTech

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers EasyIP.cpp Source File

EasyIP.cpp

00001 #include "mbed.h"
00002 #include "EasyIP.h"
00003 #include "MTSText.h"
00004 #include "MTSLog.h"
00005 #include "CellUtils.h"
00006 #include <string>
00007 
00008 using namespace mts;
00009 
00010 EasyIP::EasyIP(Radio type)
00011 {
00012     this->type = type;
00013     io = NULL;
00014     dcd = NULL;
00015     dtr = NULL;
00016     resetLine = NULL;
00017     echoMode = true;
00018     gpsEnabled = false;
00019     pppConnected = false;
00020     socketMode = TCP;
00021     socketOpened = false;
00022     socketCloseable = true;
00023     local_port = 0;
00024     local_address = "";
00025     host_port = 0;
00026 }
00027 
00028 EasyIP::~EasyIP()
00029 {
00030     if (dtr != NULL) {
00031         dtr->write(1);
00032     }
00033     
00034     delete dcd;
00035     delete dtr;
00036     delete resetLine;
00037 }
00038 
00039 //Initializes the MTS IO Buffer
00040 bool EasyIP::init(MTSBufferedIO* io)
00041 {
00042     char buf[128];
00043 
00044     if (! Cellular::init(io)) {
00045         return false;
00046     }
00047 
00048     logDebug("radio type: %s", Cellular::getRadioNames(type).c_str());
00049     //Turns on the HW flow control
00050     if(sendBasicCommand("AT+IFC=2,2", 2000) != MTS_SUCCESS) {
00051         logWarning("Failed to enable serial flow control");
00052     }
00053     // Shorten data sending timeout from 5s to 100ms
00054     // Some servers won't handle a timeout that long
00055     snprintf(buf, sizeof(buf), "AT#SCFG=1,%d,300,90,600,1", type == MTSMC_LVW2 ? 3 : 1);
00056     if (sendBasicCommand(string(buf), 2000) != MTS_SUCCESS) {
00057         logWarning("Failed to reconfigure socket timeout parameters");
00058     }
00059     return true;
00060 }
00061 
00062 bool EasyIP::connect()
00063 {
00064     //Check if APN is not set, if it is not, connect will not work.
00065     if (type == MTSMC_H5_IP || type == MTSMC_H5 || type == MTSMC_G3 || type == MTSMC_LAT1 || type == MTSMC_LEU1) {
00066         if(apn.size() == 0) {
00067             logDebug("APN is not set");
00068             return false;
00069         }
00070     }
00071     
00072     //Check if socket is open
00073     if(socketOpened) {
00074         return true;
00075     }
00076 
00077     //Check if already connected
00078     if(isConnected()) {
00079         return true;
00080     }
00081     
00082     Timer tmr;
00083     //Check Registration: AT+CREG? == 0,1
00084     tmr.start();
00085     do {
00086         Registration registration = getRegistration();
00087         if(registration != REGISTERED && registration != ROAMING) {
00088             logTrace("Not Registered [%d] ... waiting", (int)registration);
00089             wait(1);
00090         } else {
00091             break;
00092         }
00093     } while(tmr.read() < 30); 
00094     
00095     //Check RSSI: AT+CSQ
00096     tmr.reset();
00097     do {
00098         int rssi = getSignalStrength();
00099         logDebug("Signal strength: %d", rssi);
00100         if(rssi == 99 || rssi == -1) {
00101             logTrace("No Signal ... waiting");
00102             wait(1);
00103         } else {
00104             break;
00105         }
00106     } while(tmr.read() < 30);
00107 
00108     //Make PPP connection
00109     if (type == MTSMC_H5 || type == MTSMC_G3 || type == MTSMC_LAT1 || type == MTSMC_LEU1) {
00110         logDebug("Making PPP Connection Attempt. APN[%s]", apn.c_str());
00111     } else {
00112         logDebug("Making PPP Connection Attempt");
00113     }
00114     char buf[64];
00115     snprintf(buf, sizeof(buf), "AT#SGACT=%d,1", type == MTSMC_LVW2 ? 3 : 1);
00116     std::string pppResult = sendCommand(string(buf), 15000);
00117     std::vector<std::string> parts;
00118     if(pppResult.find("OK") != std::string::npos) {
00119         parts = Text::split(pppResult, "\r\n");
00120         if(parts.size() >= 2) {
00121             parts = Text::split(parts[1], " ");
00122             if (parts.size() >= 2) {
00123                 local_address = parts[1];
00124             }
00125         }
00126         logInfo("PPP Connection Established: IP[%s]", local_address.c_str());
00127         pppConnected = true;
00128 
00129     } else {
00130         snprintf(buf, sizeof(buf), "%d,1", type == MTSMC_LVW2 ? 3 : 1);
00131         pppResult = sendCommand("AT#SGACT?", 2000);
00132         if(pppResult.find(string(buf)) != std::string::npos) {
00133            logDebug("Radio is already connected");
00134            pppConnected = true;
00135         } else {
00136             logError("PPP connection attempt failed");
00137             pppConnected = false;
00138         }
00139     }
00140 
00141     return pppConnected;
00142 }
00143 
00144 void EasyIP::disconnect()
00145 {
00146     //AT#SGACT=1,0: Close PPP connection
00147     logDebug("Closing PPP Connection"); 
00148     std::string result;
00149     Timer tmr;
00150        
00151     if(socketOpened) {
00152         close(true);
00153     }
00154     
00155     //Sends AT#SGACT=1,0 command
00156     for (int y = 0; y < 5; y++) {
00157         char buf[64];
00158         snprintf(buf, sizeof(buf), "AT#SGACT=%d,0", type == MTSMC_LVW2 ? 3 : 1);
00159         Code code = sendBasicCommand(string(buf), 1000);
00160         if (code == MTS_SUCCESS) {
00161             logDebug("Successfully closed PPP Connection");
00162             break;
00163         }
00164     }
00165     
00166     /* Ensure PPP link is down, else ping commands will put radio in unknown state
00167      * (Link is not immediate in disconnection, even though OK is returned)
00168      */
00169     tmr.start();
00170     while(tmr.read() < 30) {
00171         char buf[16];
00172         snprintf(buf, sizeof(buf), "%d,0", type == MTSMC_LVW2 ? 3 : 1);
00173         result = sendCommand("AT#SGACT?", 1000);
00174         if(result.find(string(buf)) != std::string::npos) {
00175             break;
00176         } else if(result.find("ERROR") != std::string::npos) {
00177             break;
00178         } else {
00179             wait(1);
00180         }
00181     }
00182     
00183     pppConnected = false;
00184     return;
00185 }
00186 
00187 bool EasyIP::isConnected()
00188 {
00189     enum RadioState {IDLE, CONNECTING, CONNECTED, DISCONNECTED};
00190     //state flags for various connection components
00191     bool signal = false, regist = false, active = false;
00192     char buf[16];
00193     
00194     //1) Check if APN was set if we're on an HSPA radio
00195     if (type == MTSMC_H5_IP || type == MTSMC_H5 || type == MTSMC_G3 || type == MTSMC_LAT1 || type == MTSMC_LEU1) {
00196         if(apn.size() == 0) {
00197             logDebug("APN is not set");
00198             return false;
00199         }
00200     }
00201     
00202     //2) Check that we do not have a live connection up
00203     if (socketOpened) {
00204         logDebug("Socket is opened");
00205         return true;
00206     }
00207     
00208     //3) Query the radio
00209     int rssi = getSignalStrength();
00210     if (rssi == 99 || rssi == -1) {
00211         //Signal strength is nonexistent
00212         signal = false;
00213     } else {
00214         signal = true;
00215     }
00216     
00217     Registration creg = getRegistration();
00218     if (creg == REGISTERED) {
00219         regist = true;
00220     } else {
00221         regist = false;
00222     }
00223     
00224     string reply = sendCommand("AT#SGACT?", 1000);
00225     snprintf(buf, sizeof(buf), "%d,1", type == MTSMC_LVW2 ? 3 : 1);
00226     if (reply.find(string(buf)) != std::string::npos) {
00227         active = true;
00228     } else {
00229         active = false;
00230     }
00231     
00232     //Updates pppConnected to reflect current connection state
00233     RadioState state;
00234     bool ppp = pppConnected;
00235     if (signal && regist && active) {
00236         state = CONNECTED;
00237         pppConnected = true;
00238     } else if (signal && !regist && !active) {
00239         state = IDLE;
00240         pppConnected = false;
00241     } else if (active) {
00242         state = CONNECTING;
00243     } else {
00244         state = DISCONNECTED;
00245         pppConnected = false;
00246     }
00247     
00248     //Compares current connection state with previous pppConnected variable state
00249     if (!ppp && state == CONNECTED) {
00250         logWarning("Internal PPP state tracking differs from radio (DISCONNECTED:CONNECTED)");
00251     } else if (ppp && state != CONNECTED) {
00252         string stateStr;
00253         switch (state) {
00254             case IDLE:
00255                 stateStr = "IDLE";
00256                 break;
00257             case CONNECTING:
00258                 stateStr = "CONNECTING";
00259                 break;
00260             case DISCONNECTED:
00261                 stateStr = "DISCONNECTED";
00262                 break;
00263             case CONNECTED:
00264                 stateStr = "CONNECTED";
00265                 break;
00266             default:
00267                 stateStr = "UKNOWN";
00268                 break;
00269         }
00270         logWarning("Internal PPP state tracking differs from radio (CONNECTED:%s)", stateStr.c_str());
00271     }
00272     
00273     return pppConnected;
00274 }
00275 
00276 void EasyIP::reset()
00277 {
00278     disconnect();
00279     
00280     if(sendBasicCommand("AT#REBOOT", 10000) != MTS_SUCCESS) {
00281         logError("Socket Modem did not accept RESET command");
00282     } else {
00283         logWarning("Socket Modem is resetting, allow 30 seconds for it to come back");
00284         return;
00285     }
00286 }
00287 
00288 //Opens socket connection
00289 bool EasyIP::open(const std::string& address, unsigned int port, Mode mode)
00290 {
00291     char sOpenSocketCmd[256] = {0}; //String for AT command
00292     std::string sMode = "";
00293     int typeSocket = 0;
00294     int closeType = 0;
00295     
00296     //1) Check that we do not have a live connection up
00297     if(socketOpened) {
00298         //Check that the address, port, and mode match
00299         if(host_address != address || host_port != port || socketMode != mode) {
00300             if(socketMode == TCP) {
00301                 logError("TCP socket already opened [%s:%d]", host_address.c_str(), host_port);
00302             } else {
00303                 logError("UDP socket already opened [%s:%d]", host_address.c_str(), host_port);
00304             }
00305             return false;
00306         }
00307 
00308         logDebug("Socket already opened");
00309         return true;
00310     }
00311 
00312     //2) Check Parameters
00313     if(port > 65535) {
00314         logError("port out of range (0-65535)");
00315         return false;
00316     }
00317     
00318     if(type == MTSMC_EV3 || type == MTSMC_LAT1 || type == MTSMC_LEU1 || type == MTSMC_LVW2) {
00319         if(!local_port) {
00320             logDebug("Local port set to 1, port 0 not supported for %s", getRadioNames(type).c_str());
00321             local_port = 1;
00322         }
00323     }
00324 
00325     //3) Check PPP connection
00326     if(!isConnected()) {
00327         logError("PPP not established.  Attempting to connect");
00328         if(!connect()) {
00329             logError("PPP connection failed");
00330             return false;
00331         } else {
00332             logDebug("PPP connection established");
00333         }
00334     }
00335     
00336     //4) Set escape sequence to not be transmitted through socket
00337     if(sendBasicCommand("AT#SKIPESC=1", 2000) != MTS_SUCCESS) {
00338         logWarning("Failed to disable escape sequence transmission on data mode suspension");
00339     }
00340     
00341     if(mode == TCP) {
00342         typeSocket = 0;
00343         sMode = "TCP";
00344     } else {
00345         typeSocket = 1;
00346         sMode = "UDP";
00347     }
00348     
00349     if(socketCloseable) {
00350         closeType = 0;
00351     } else {
00352         closeType = 255;
00353     }
00354     
00355     //5) Open Socket  
00356     sprintf(sOpenSocketCmd, "AT#SD=1,%d,%d,\"%s\",%d,%d,0", typeSocket, port, address.c_str(), closeType, local_port);
00357     std::string response = sendCommand(sOpenSocketCmd, 60000);
00358     
00359     if(response.find("CONNECT") != std::string::npos) {
00360         host_address = address;
00361         host_port = port;
00362         
00363         logInfo("Opened %s Socket [%s:%d]", sMode.c_str(), address.c_str(), port);
00364         socketOpened = true;
00365         socketMode = mode;
00366     } else {
00367         logWarning("Unable to open %s Socket [%s:%d]", sMode.c_str(), address.c_str(), port);
00368         socketOpened = false;
00369     }
00370     
00371     return socketOpened;
00372 }
00373 
00374 //Closes socket connection
00375 bool EasyIP::close(bool shutdown)
00376 {
00377     
00378     if(io == NULL) {
00379         logError("MTSBufferedIO not set");
00380         return false;
00381     }
00382 
00383     if(!socketOpened) {
00384         logWarning("Socket close() called, but socket was not open");
00385         return true;
00386     }
00387 
00388     if(!socketCloseable) {
00389         logError("Socket is not closeable");
00390         return false;
00391     }
00392     
00393     if(!sendEscapeCommand()) {
00394         logError("Failed to exit online mode");
00395         return false;
00396     } else {
00397         socketOpened = false;
00398     }
00399     
00400     if (sendBasicCommand("AT#SH=1", 2000) != MTS_SUCCESS) {
00401         logDebug("Failed to close socket connection");
00402     }
00403     
00404     //Clear receive buffer
00405     if (shutdown) {
00406         int counter = 0;
00407         char tmp[256];
00408         do {
00409             if(socketOpened == false) {
00410                 break;
00411             }
00412             read(tmp, 256, 1000);
00413         } while(counter++ < 10);
00414     
00415         io->rxClear();
00416         io->txClear();
00417     }
00418 
00419     return !socketOpened;
00420 }
00421 
00422 //Read from socket
00423 int EasyIP::read(char* data, int max, int timeout)
00424 {
00425     if(io == NULL) {
00426         logError("MTSBufferedIO not set");
00427         return -1;
00428     }
00429 
00430     //Check that nothing is in the rx buffer
00431     if(!socketOpened && !io->readable()) {
00432         logError("Socket is not open");
00433         return -1;
00434     }
00435 
00436     int bytesRead = 0;
00437 
00438     if(timeout >= 0) {
00439         bytesRead = io->read(data, max, static_cast<unsigned int>(timeout));
00440     } else {
00441         bytesRead = io->read(data, max);
00442     }
00443     
00444     //Scan for socket closed message
00445     if(bytesRead > 0 && socketCloseable) {
00446         for(int i = 0; i < bytesRead; i++) {
00447             if(data[i] == 'N') {
00448                 if(strstr(&data[i], "NO CARRIER")) {
00449                     logTrace("Found socket closed message. Checking validity");
00450                     //Close socket and Cut Off End of Message
00451                     socketOpened = socketCheck(); //Verifies legitimacy of socket disconnect
00452                     if(socketOpened) {
00453                         logDebug("Socket still open");
00454                         continue;
00455                     } else {
00456                         logDebug("Socket closed");
00457                         data[i] = '\0';
00458                         bytesRead = i;
00459                         break;
00460                     }
00461                 }
00462             }
00463         }
00464     }
00465     return bytesRead;
00466 }
00467 
00468 //Write to socket
00469 int EasyIP::write(const char* data, int length, int timeout)
00470 {
00471     if(io == NULL) {
00472         logError("MTSBufferedIO not set");
00473         return -1;
00474     }
00475 
00476     if(!socketOpened) {
00477         logError("Socket is not open");
00478         return -1;
00479     }
00480 
00481     int bytesWritten = 0;
00482     int size = length;
00483     int failedWrites = 0;
00484     if(timeout >= 0) {
00485         Timer tmr;
00486         tmr.start();
00487         do {
00488             int available = io->writeable();
00489             if (available > 0) {
00490                 size = mts_min(available, length - bytesWritten);
00491                 bytesWritten += io->write(&data[bytesWritten], size);
00492             } else {
00493                 wait(0.05);
00494             }
00495         } while (tmr.read_ms() <= timeout && bytesWritten < length);
00496     } else {
00497         //If timeout is -1:
00498         do {
00499             int available = io->writeable();
00500             if(available > 0) {
00501                 size = mts_min(available, length - bytesWritten);
00502                 int currentWritten = io->write(&data[bytesWritten], size);
00503                 bytesWritten += currentWritten;
00504                 if(!currentWritten) {
00505                     failedWrites++;
00506                 }
00507                 if(failedWrites > 10) {
00508                     logError("Couldn't write any characters");
00509                     return bytesWritten;
00510                 }
00511             } else {
00512                 wait(0.05);
00513             }
00514         } while (bytesWritten < length); 
00515     }
00516     return bytesWritten;
00517 }
00518 
00519 Code EasyIP::setApn(const std::string& apn)
00520 {
00521     if (type == MTSMC_H5 || type == MTSMC_G3) {
00522          //CGDCONT has options: IP,PPP,IPv6
00523         Code code = sendBasicCommand("AT+CGDCONT=1,IP," + apn, 1000);
00524         if (code != MTS_SUCCESS) {
00525             return code;
00526         }
00527         this->apn = apn;
00528         return code;
00529     } else if (type == MTSMC_LAT1 || type == MTSMC_LEU1) {
00530          //CGDCONT has options: IP,PPP,IPv6
00531         Code code = sendBasicCommand("AT+CGDCONT=1,\"IP\",\"" + apn + "\"", 1000);
00532         if (code != MTS_SUCCESS) {
00533             return code;
00534         }
00535         this->apn = apn;
00536         return code;
00537     } else {
00538         logInfo("CDMA radios don't need an APN");
00539         return MTS_SUCCESS;
00540     }
00541 }
00542 
00543 bool EasyIP::ping(const std::string& address)
00544 {
00545     char buffer[256] = {0};
00546     std::vector<std::string> parts;
00547     int TTL=0;
00548     int Timeout=0;
00549     
00550     //Format parameters for sending to radio
00551     sprintf(buffer, "AT#PING=%s,1,32,%d", address.c_str(), (PINGDELAY*10));
00552     
00553     for(int pngs=0; pngs<PINGNUM; pngs++) {
00554         std::string response = sendCommand(buffer, (PINGDELAY*2000)); //Send 1 ping
00555         if(response.empty() || response.find("ERROR") != std::string::npos) {
00556             continue; //Skip current loop if send command fails
00557         }
00558         parts = Text::split(response, "\r\n");
00559         if(parts.size() < 2) {
00560             continue;
00561         }
00562         parts = Text::split(parts[1], ",");
00563         if(parts.size() < 4) {
00564             continue;
00565         }
00566         //Parse TTL and Timeout values
00567         Timeout = std::atoi(parts[2].c_str());
00568         TTL = std::atoi(parts[3].c_str());
00569                 
00570         if((Timeout < 600) && (TTL < 255)) {
00571             return true;
00572         }
00573     }   
00574     return false;
00575 }
00576 
00577 bool EasyIP::sendEscapeCommand()
00578 {
00579     //string Cellular::sendCommand(const std::string& command, unsigned int timeoutMillis, char esc)
00580     if(io == NULL) {
00581         logError("MTSBufferedIO not set");
00582         return false;
00583     }
00584     if(!socketOpened) {
00585         logError("Socket is not open.");
00586         return false;
00587     }
00588     
00589     if(!socketCloseable) {
00590         logError("Socket is not closeable");
00591         return false;
00592     }
00593     
00594     io->rxClear();
00595     io->txClear();
00596     
00597     std::string result;
00598     unsigned int timeoutMillis = 10000;
00599     //Attempt to write command
00600     //Format for +++ command is 1 second wait, send +++, then another second wait
00601     wait(1.2); 
00602     if(io->write("+++", 3, timeoutMillis) != 3) {
00603         //Failed to write command
00604         logError("failed to send command to radio within %d milliseconds", timeoutMillis);
00605         return false;
00606     }
00607     
00608     Timer tmr;
00609     char tmp[256];
00610     tmp[255] = 0;
00611     bool done = false;
00612     bool exitmode = false;
00613     tmr.start();
00614     do {
00615         //Make a non-blocking read call by passing timeout of zero
00616         int size = io->read(tmp,255,0);    //1 less than allocated (timeout is instant)
00617         if(size > 0) {
00618             result.append(tmp, size);
00619         }
00620         if(result.find("OK\r\n") != std::string::npos) {
00621             exitmode = true;
00622             done = true;
00623         } else if(result.find("NO CARRIER\r\n") != std::string::npos) {
00624             socketOpened = false;
00625             exitmode = true;
00626             done = true;
00627         } else if(result.find("ERROR") != std::string::npos) {
00628             exitmode = false;
00629             done = true;
00630         }
00631         if(tmr.read_ms() >= timeoutMillis) {
00632             logDebug("Escape sequence [+++] timed out after %d milliseconds", timeoutMillis);
00633             exitmode = true;
00634             done = true;
00635         }
00636     } while (!done);
00637     
00638     wait(0.1); //Without a slight wait time after receiving OK, radio would
00639                //fail to correctly receive and respond to the next AT command
00640     return exitmode;
00641 }
00642 
00643 bool EasyIP::socketCheck() {
00644     enum SocketStatus {SOCKETCLOSED = 0, SOCKETACTIVEDATA = 1, SOCKETSUSPEND = 2, SOCKETSUSPENDDATA = 3, SOCKETLISTEN = 4, SOCKETINCOMING = 5, ERROR = 9};
00645     bool status = false;
00646     int socketInfo = ERROR;
00647     std::vector<std::string> params;
00648     
00649     //Goes from data mode to command mode
00650     if(sendEscapeCommand()) {
00651         std::string reply = sendCommand("AT#SS=1", 2000);
00652         if(reply.find("OK") != std::string::npos) {
00653             //Found valid response
00654             params = Text::split(reply, "\r\n");
00655             params = Text::split(params[1], ",");
00656             socketInfo = atoi(params[1].c_str());
00657         } else {
00658             logError("Could not determine socket status[%d]",socketInfo);
00659             socketInfo = ERROR;
00660         }
00661     } else {
00662         status = false; //Return value of socketOpened when checking
00663     }
00664     
00665     //Check socket status query
00666     if(socketInfo == SOCKETINCOMING || socketInfo == SOCKETACTIVEDATA || socketInfo == SOCKETSUSPEND || socketInfo == SOCKETSUSPENDDATA || socketInfo == SOCKETLISTEN) { //Socket opened responses
00667         status = true;
00668     } else if(socketInfo == SOCKETCLOSED || socketInfo == SOCKETINCOMING) {
00669         status = false;
00670     } else {
00671         logError("Could not determine socket status[%d]",socketInfo);
00672         status = false;
00673     }
00674     
00675     //Reconnect to active socket if able
00676     if(status) {
00677         std::string reconnect = sendCommand("AT#SO=1", 2000);
00678         if(reconnect.find("CONNECT") != std::string::npos || reconnect.find("OK") != std::string::npos) {
00679         } else {
00680             logError("Failed to resume socket connection");
00681         }
00682     }
00683     return status;
00684 }
00685 
00686 bool EasyIP::GPSenable() {
00687 //The HE910 returns an ERROR if you try to enable when it is already enabled.
00688 // That's why we need to check if GPS is enabled before enabling it.
00689     if(GPSenabled()) {
00690         logInfo("GPS was already enabled.");
00691         return true;
00692     }
00693 //The LE910-NAG requires AT$GPSSLSR=2,3 to enable GPS but can use AT$GPSP=0 to disable it.    
00694     if(type == MTSMC_LAT1){
00695         Code code = sendBasicCommand("AT$GPSSLSR=2,3", 2000);
00696         if (code == MTS_SUCCESS) {
00697             gpsEnabled = true;        
00698             logInfo("GPS enabled.");
00699             return true;
00700         } else {
00701             logError("Enable GPS failed!");        
00702             return false;
00703         }        
00704     } else {
00705         Code code = sendBasicCommand("AT$GPSP=1", 2000);
00706         if (code == MTS_SUCCESS) {
00707             gpsEnabled = true;        
00708             logInfo("GPS enabled.");
00709             return true;
00710         } else {
00711             logError("Enable GPS failed.");
00712             return false;
00713         }
00714     }
00715 }
00716 
00717 bool EasyIP::GPSdisable() {
00718 // The HE910 returns an ERROR if you try to disable when it is already disabled.
00719 // That's why we need to check if GPS is disabled before disabling it.
00720     if(!GPSenabled()) {
00721         logInfo("GPS was already disabled.");
00722         return true;
00723     }
00724     Code code = sendBasicCommand("AT$GPSP=0", 2000);
00725     if (code == MTS_SUCCESS) {
00726         gpsEnabled = false;        
00727         logInfo("GPS disabled.");
00728         return true;
00729     } else {
00730         logError("Disable GPS failed.");
00731         return false;
00732     }
00733 }
00734 
00735 bool EasyIP::GPSenabled() {
00736     std::string reply = sendCommand("AT$GPSP?", 1000);
00737     if(reply.find("1") != std::string::npos) {
00738         gpsEnabled = true;
00739         return true;
00740     } else {
00741         gpsEnabled = false;
00742         return false;
00743     }
00744 }
00745 
00746 Cellular::gpsData EasyIP::GPSgetPosition(){
00747     enum gpsFields{time, latitude, longitude, hdop, altitude, fix, cog, kmhr, knots, date, satellites, numOfFields };
00748     Cellular::gpsData position;
00749     if(!gpsEnabled) {
00750         logError("GPS is disabled... can't get position.");
00751         position.success = false;
00752         return position;
00753     }
00754     // Get the position information in string format.
00755     std::string gps = sendCommand("AT$GPSACP?", 1000);
00756     if(gps.find("OK") != std::string::npos) {
00757         position.success = true;
00758         // Remove echoed AT$GPSACP and leading non position characters.
00759         gps.erase(0,22);
00760         // Remove trailing CR/LF, CR/LF, OK and CR/LF.
00761         gps.erase(gps.end()-8, gps.end());
00762         // Split remaining data and load into corresponding structure fields.
00763         std::vector<std::string> gpsParts = Text::split(gps, ',');
00764         // Check size.
00765         if(gpsParts.size() != numOfFields) {
00766             logError("Expected %d fields but there are %d fields in \"%s\"", numOfFields, gpsParts.size(), gps.c_str());
00767             position.success = false;
00768             return position; 
00769         }
00770         position.latitude = gpsParts[latitude];
00771         position.longitude = gpsParts[longitude];
00772         position.hdop = atof(gpsParts[hdop].c_str());
00773         position.altitude = atof(gpsParts[altitude].c_str());
00774         position.fix = atoi(gpsParts[fix].c_str());
00775         position.cog = gpsParts[cog];
00776         position.kmhr = atof(gpsParts[kmhr].c_str());
00777         position.knots = atof(gpsParts[knots].c_str());
00778         position.satellites = atoi(gpsParts[satellites].c_str());
00779         if((gpsParts[date].size() == 6) && (gpsParts[time].size() == 10)) {
00780             position.timestamp = gpsParts[date].substr(4,2) + "/" + gpsParts[date].substr(2,2) + 
00781             "/" + gpsParts[date].substr(0,2) + ", " + gpsParts[time].substr(0,2) + 
00782             ":" + gpsParts[time].substr(2,2) + ":" + gpsParts[time].substr(4,6);        
00783         }
00784         return position;     
00785     } else {
00786         position.success = false;
00787         logError("NO \"OK\" returned from GPS position command \"AT$GPSACP?\".");
00788         return position;
00789     }
00790 }   
00791     
00792 bool EasyIP::GPSgotFix() {
00793     if(!gpsEnabled) {
00794         logError("GPS is disabled... can't get fix.");
00795         return false;
00796     }
00797     Cellular::gpsData position = GPSgetPosition();
00798     if(!position.success) {
00799         return false;
00800     } else if(position.fix < 2){
00801         logWarning("No GPS fix. GPS fix can take a few minutes. Check GPS antenna attachment and placement.");
00802         return false;
00803     } else {
00804         logInfo("Got GPS fix.");
00805         return true;
00806     }
00807 }