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 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 || type == MTQ_LVW3) ? 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 || type == MTQ_LVW3) ? 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 || type == MTQ_LVW3) ? 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 || type == MTQ_LVW3) ? 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 || type == MTQ_LVW3) ? 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 || type == MTQ_LVW3) ? 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 || type == MTQ_LAT3) {
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 if (type == MTQ_MAT1) {
00538         Code code = sendBasicCommand("AT+CGDCONT=1,\"IPV4V6\",\"" + apn + "\"", 1000);
00539         if (code != MTS_SUCCESS) {
00540             return code;
00541         }
00542         this->apn = apn;
00543         return code;
00544     } else if (type == MTQ_MVW1 || type == MTQ_LVW3) {
00545         logInfo("Radio does not need an APN");
00546         return MTS_SUCCESS;       
00547     } else {
00548         logInfo("CDMA radios do not need an APN");
00549         return MTS_SUCCESS;
00550     }
00551 }
00552 
00553 bool EasyIP::ping(const std::string& address)
00554 {
00555     char buffer[256] = {0};
00556     std::vector<std::string> parts;
00557     int TTL=0;
00558     int Timeout=0;
00559     
00560     //Format parameters for sending to radio
00561     sprintf(buffer, "AT#PING=%s,1,32,%d", address.c_str(), (PINGDELAY*10));
00562     
00563     for(int pngs=0; pngs<PINGNUM; pngs++) {
00564         std::string response = sendCommand(buffer, (PINGDELAY*2000)); //Send 1 ping
00565         if(response.empty() || response.find("ERROR") != std::string::npos) {
00566             continue; //Skip current loop if send command fails
00567         }
00568         parts = Text::split(response, "\r\n");
00569         if(parts.size() < 2) {
00570             continue;
00571         }
00572         parts = Text::split(parts[1], ",");
00573         if(parts.size() < 4) {
00574             continue;
00575         }
00576         //Parse TTL and Timeout values
00577         Timeout = std::atoi(parts[2].c_str());
00578         TTL = std::atoi(parts[3].c_str());
00579                 
00580         if((Timeout < 600) && (TTL < 255)) {
00581             return true;
00582         }
00583     }   
00584     return false;
00585 }
00586 
00587 bool EasyIP::sendEscapeCommand()
00588 {
00589     //string Cellular::sendCommand(const std::string& command, unsigned int timeoutMillis, char esc)
00590     if(io == NULL) {
00591         logError("MTSBufferedIO not set");
00592         return false;
00593     }
00594     if(!socketOpened) {
00595         logError("Socket is not open.");
00596         return false;
00597     }
00598     
00599     if(!socketCloseable) {
00600         logError("Socket is not closeable");
00601         return false;
00602     }
00603     
00604     io->rxClear();
00605     io->txClear();
00606     
00607     std::string result;
00608     unsigned int timeoutMillis = 10000;
00609     //Attempt to write command
00610     //Format for +++ command is 1 second wait, send +++, then another second wait
00611     wait(1.2); 
00612     if(io->write("+++", 3, timeoutMillis) != 3) {
00613         //Failed to write command
00614         logError("failed to send command to radio within %d milliseconds", timeoutMillis);
00615         return false;
00616     }
00617     
00618     Timer tmr;
00619     char tmp[256];
00620     tmp[255] = 0;
00621     bool done = false;
00622     bool exitmode = false;
00623     tmr.start();
00624     do {
00625         //Make a non-blocking read call by passing timeout of zero
00626         int size = io->read(tmp,255,0);    //1 less than allocated (timeout is instant)
00627         if(size > 0) {
00628             result.append(tmp, size);
00629         }
00630         if(result.find("OK\r\n") != std::string::npos) {
00631             exitmode = true;
00632             done = true;
00633         } else if(result.find("NO CARRIER\r\n") != std::string::npos) {
00634             socketOpened = false;
00635             exitmode = true;
00636             done = true;
00637         } else if(result.find("ERROR") != std::string::npos) {
00638             exitmode = false;
00639             done = true;
00640         }
00641         if(tmr.read_ms() >= timeoutMillis) {
00642             logDebug("Escape sequence [+++] timed out after %d milliseconds", timeoutMillis);
00643             exitmode = true;
00644             done = true;
00645         }
00646     } while (!done);
00647     
00648     wait(0.1); //Without a slight wait time after receiving OK, radio would
00649                //fail to correctly receive and respond to the next AT command
00650     return exitmode;
00651 }
00652 
00653 bool EasyIP::socketCheck() {
00654     enum SocketStatus {SOCKETCLOSED = 0, SOCKETACTIVEDATA = 1, SOCKETSUSPEND = 2, SOCKETSUSPENDDATA = 3, SOCKETLISTEN = 4, SOCKETINCOMING = 5, ERROR = 9};
00655     bool status = false;
00656     int socketInfo = ERROR;
00657     std::vector<std::string> params;
00658     
00659     //Goes from data mode to command mode
00660     if(sendEscapeCommand()) {
00661         std::string reply = sendCommand("AT#SS=1", 2000);
00662         if(reply.find("OK") != std::string::npos) {
00663             //Found valid response
00664             params = Text::split(reply, "\r\n");
00665             params = Text::split(params[1], ",");
00666             socketInfo = atoi(params[1].c_str());
00667         } else {
00668             logError("Could not determine socket status[%d]",socketInfo);
00669             socketInfo = ERROR;
00670         }
00671     } else {
00672         status = false; //Return value of socketOpened when checking
00673     }
00674     
00675     //Check socket status query
00676     if(socketInfo == SOCKETINCOMING || socketInfo == SOCKETACTIVEDATA || socketInfo == SOCKETSUSPEND || socketInfo == SOCKETSUSPENDDATA || socketInfo == SOCKETLISTEN) { //Socket opened responses
00677         status = true;
00678     } else if(socketInfo == SOCKETCLOSED || socketInfo == SOCKETINCOMING) {
00679         status = false;
00680     } else {
00681         logError("Could not determine socket status[%d]",socketInfo);
00682         status = false;
00683     }
00684     
00685     //Reconnect to active socket if able
00686     if(status) {
00687         std::string reconnect = sendCommand("AT#SO=1", 2000);
00688         if(reconnect.find("CONNECT") != std::string::npos || reconnect.find("OK") != std::string::npos) {
00689         } else {
00690             logError("Failed to resume socket connection");
00691         }
00692     }
00693     return status;
00694 }
00695 
00696 bool EasyIP::GPSenable() {
00697 //The HE910 returns an ERROR if you try to enable when it is already enabled.
00698 // That's why we need to check if GPS is enabled before enabling it.
00699     if(GPSenabled()) {
00700         logInfo("GPS was already enabled.");
00701         return true;
00702     }
00703 //The LE910-NAG requires AT$GPSSLSR=2,3 to enable GPS but can use AT$GPSP=0 to disable it.    
00704     if(type == MTSMC_LAT1){
00705         Code code = sendBasicCommand("AT$GPSSLSR=2,3", 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     } else {
00715         Code code = sendBasicCommand("AT$GPSP=1", 2000);
00716         if (code == MTS_SUCCESS) {
00717             gpsEnabled = true;        
00718             logInfo("GPS enabled.");
00719             return true;
00720         } else {
00721             logError("Enable GPS failed.");
00722             return false;
00723         }
00724     }
00725 }
00726 
00727 bool EasyIP::GPSdisable() {
00728 // The HE910 returns an ERROR if you try to disable when it is already disabled.
00729 // That's why we need to check if GPS is disabled before disabling it.
00730     if(!GPSenabled()) {
00731         logInfo("GPS was already disabled.");
00732         return true;
00733     }
00734     Code code = sendBasicCommand("AT$GPSP=0", 2000);
00735     if (code == MTS_SUCCESS) {
00736         gpsEnabled = false;        
00737         logInfo("GPS disabled.");
00738         return true;
00739     } else {
00740         logError("Disable GPS failed.");
00741         return false;
00742     }
00743 }
00744 
00745 bool EasyIP::GPSenabled() {
00746     std::string reply = sendCommand("AT$GPSP?", 1000);
00747     if(reply.find("1") != std::string::npos) {
00748         gpsEnabled = true;
00749         return true;
00750     } else {
00751         gpsEnabled = false;
00752         return false;
00753     }
00754 }
00755 
00756 Cellular::gpsData EasyIP::GPSgetPosition(){
00757     enum gpsFields{time, latitude, longitude, hdop, altitude, fix, cog, kmhr, knots, date, satellites, numOfFields };
00758     Cellular::gpsData position;
00759     if(!gpsEnabled) {
00760         logError("GPS is disabled... can't get position.");
00761         position.success = false;
00762         return position;
00763     }
00764     // Get the position information in string format.
00765     std::string gps = sendCommand("AT$GPSACP?", 1000);
00766     if(gps.find("OK") != std::string::npos) {
00767         position.success = true;
00768         // Remove echoed AT$GPSACP and leading non position characters.
00769         gps.erase(0,22);
00770         // Remove trailing CR/LF, CR/LF, OK and CR/LF.
00771         gps.erase(gps.end()-8, gps.end());
00772         // Split remaining data and load into corresponding structure fields.
00773         std::vector<std::string> gpsParts = Text::split(gps, ',');
00774         // Check size.
00775         if(gpsParts.size() != numOfFields) {
00776             logError("Expected %d fields but there are %d fields in \"%s\"", numOfFields, gpsParts.size(), gps.c_str());
00777             position.success = false;
00778             return position; 
00779         }
00780         position.latitude = gpsParts[latitude];
00781         position.longitude = gpsParts[longitude];
00782         position.hdop = atof(gpsParts[hdop].c_str());
00783         position.altitude = atof(gpsParts[altitude].c_str());
00784         position.fix = atoi(gpsParts[fix].c_str());
00785         position.cog = gpsParts[cog];
00786         position.kmhr = atof(gpsParts[kmhr].c_str());
00787         position.knots = atof(gpsParts[knots].c_str());
00788         position.satellites = atoi(gpsParts[satellites].c_str());
00789         if((gpsParts[date].size() == 6) && (gpsParts[time].size() == 10)) {
00790             position.timestamp = gpsParts[date].substr(4,2) + "/" + gpsParts[date].substr(2,2) + 
00791             "/" + gpsParts[date].substr(0,2) + ", " + gpsParts[time].substr(0,2) + 
00792             ":" + gpsParts[time].substr(2,2) + ":" + gpsParts[time].substr(4,6);        
00793         }
00794         return position;     
00795     } else {
00796         position.success = false;
00797         logError("NO \"OK\" returned from GPS position command \"AT$GPSACP?\".");
00798         return position;
00799     }
00800 }   
00801     
00802 bool EasyIP::GPSgotFix() {
00803     if(!gpsEnabled) {
00804         logError("GPS is disabled... can't get fix.");
00805         return false;
00806     }
00807     Cellular::gpsData position = GPSgetPosition();
00808     if(!position.success) {
00809         return false;
00810     } else if(position.fix < 2){
00811         logWarning("No GPS fix. GPS fix can take a few minutes. Check GPS antenna attachment and placement.");
00812         return false;
00813     } else {
00814         logInfo("Got GPS fix.");
00815         return true;
00816     }
00817 }