Version using RawSerial instead of Serial (thread safe)

Fork of FONA_Cellphone_Library by Dream Team

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Adafruit_FONA.cpp Source File

Adafruit_FONA.cpp

00001 /***************************************************
00002   This is a library for our Adafruit FONA Cellular Module
00003 
00004   Designed specifically to work with the Adafruit FONA
00005   ----> http://www.adafruit.com/products/1946
00006   ----> http://www.adafruit.com/products/1963
00007 
00008   These displays use TTL Serial to communicate, 2 pins are required to
00009   interface
00010   Adafruit invests time and resources providing this open source code,
00011   please support Adafruit and open-source hardware by purchasing
00012   products from Adafruit!
00013 
00014   Written by Limor Fried/Ladyada for Adafruit Industries.
00015   BSD license, all text above must be included in any redistribution
00016  ****************************************************/
00017  
00018  /*
00019   *  Modified by George Tzintzarov & Jesse Baker 03/14/2016 for use in mbed LPC1768
00020   */
00021 #include <algorithm>
00022 #include "Adafruit_FONA.h"
00023 
00024 #define HIGH 1
00025 #define LOW 0
00026 
00027 /*
00028 Notes George is taking:
00029 sendCheckReply returns a boolean where its true when FONA responds with the string of its second input
00030 
00031 */
00032 
00033 
00034 bool Adafruit_FONA::begin(int baudrate) {
00035     mySerial.baud(baudrate); //set the baud rate of the fona serial connection
00036     mySerial.attach(this, &Adafruit_FONA::onSerialDataReceived, Serial::RxIrq); //attached onSerialDataReceived as Serial receive interrupt
00037     
00038     // INIT Reboot process
00039     _rstpin = HIGH;
00040     Thread::wait(10);
00041     _rstpin = LOW;
00042     Thread::wait(100);
00043     _rstpin = HIGH;
00044     
00045     // give 3 seconds to reboot
00046     Thread::wait(3000);
00047     
00048     // flushes the serial port
00049     while (readable()) getc();
00050     
00051     // Make sure FONA is alive
00052     sendCheckReply("AT", "OK");
00053     Thread::wait(100);
00054     sendCheckReply("AT", "OK");
00055     Thread::wait(100);
00056     sendCheckReply("AT", "OK");
00057     Thread::wait(100);
00058     
00059     // turn off Echo!
00060     sendCheckReply("ATE0", "OK");
00061     Thread::wait(100);
00062     
00063     // Just checks if the FONA even responds, if it doesnt, then return false
00064     if (! sendCheckReply("ATE0", "OK")) {
00065         return false;
00066     }
00067     
00068     return true;
00069 }
00070 
00071 void Adafruit_FONA::setEventListener(EventListener *eventListener) {
00072     this->eventListener = eventListener;
00073 }
00074 
00075 /********* Stream ********************************************/
00076 
00077 int Adafruit_FONA::_putc(int value) {
00078     return mySerial.putc(value);
00079 }
00080 
00081 int Adafruit_FONA::_getc() {
00082     __disable_irq(); // Start Critical Section - don't interrupt while changing global buffer variables
00083     
00084     // Wait for data if the buffer is empty
00085     if (isRxBufferEmpty()) {
00086         __enable_irq(); // End Critical Section - need to allow rx interrupt to get new characters for buffer
00087         
00088         while(isRxBufferEmpty());
00089         
00090         __disable_irq(); // Start Critical Section - don't interrupt while changing global buffer variables
00091     }
00092     
00093     int data = rxBuffer[rxBufferOutIndex];
00094     incrementRxBufferOutIndex();
00095     
00096     __enable_irq(); // End Critical Section
00097     
00098     return data;
00099 }
00100 
00101 int Adafruit_FONA::readable() {
00102     return !isRxBufferEmpty();
00103 }
00104 
00105 void Adafruit_FONA::onSerialDataReceived() {
00106     while (mySerial.readable() && !isRxBufferFull()) {
00107         int data = mySerial.getc();
00108         rxBuffer[rxBufferInIndex] = data;
00109         
00110         //
00111         // Analyze the received data in order to detect events like RING or NO CARRIER
00112         //
00113         
00114         // Copy the data in the current line
00115         if (currentReceivedLineSize < RX_BUFFER_SIZE && data != '\r' && data != '\n') {
00116             currentReceivedLine[currentReceivedLineSize] = (char) data;
00117             currentReceivedLineSize++;
00118         }
00119         
00120         // Check if the line is complete
00121         if (data == '\n') {
00122             currentReceivedLine[currentReceivedLineSize] = 0;
00123             
00124             if (eventListener != NULL) {
00125                 // Check if we have a special event
00126                 if (strcmp(currentReceivedLine, "RING") == 0) {
00127                     eventListener->onRing();
00128                 } else if (strcmp(currentReceivedLine, "NO CARRIER") == 0) {
00129                     eventListener->onNoCarrier();
00130                 }
00131             }
00132             
00133             currentReceivedLineSize = 0;
00134         }
00135         
00136         incrementRxBufferInIndex();
00137     }
00138 }
00139 
00140 /********* Real Time Clock ********************************************/
00141 
00142 bool Adafruit_FONA::enableRTC(uint8_t i) {
00143     if (! sendCheckReply("AT+CLTS=", i, "OK")) 
00144         return false;
00145     return sendCheckReply("AT&W", "OK");
00146 }
00147 
00148 /********* BATTERY & ADC ********************************************/
00149 
00150 /* returns value in mV (uint16_t) */
00151 bool Adafruit_FONA::getBattVoltage(uint16_t *v) {
00152     return sendParseReply("AT+CBC", "+CBC: ", v, ',', 2);
00153 }
00154 
00155 /* returns the percentage charge of battery as reported by sim800 */
00156 bool Adafruit_FONA::getBattPercent(uint16_t *p) {
00157     return sendParseReply("AT+CBC", "+CBC: ", p, ',', 1);
00158 }
00159 
00160 bool Adafruit_FONA::getADCVoltage(uint16_t *v) {
00161     return sendParseReply("AT+CADC?", "+CADC: 1,", v);
00162 }
00163 
00164 /********* SIM ***********************************************************/
00165 
00166 bool Adafruit_FONA::unlockSIM(char *pin)
00167 {
00168     char sendbuff[14] = "AT+CPIN=";
00169     sendbuff[8] = pin[0];
00170     sendbuff[9] = pin[1];
00171     sendbuff[10] = pin[2];
00172     sendbuff[11] = pin[3];
00173     sendbuff[12] = NULL;
00174     
00175     return sendCheckReply(sendbuff, "OK");
00176 }
00177 
00178 uint8_t Adafruit_FONA::getSIMCCID(char *ccid) {
00179     getReply("AT+CCID");
00180     // up to 20 chars
00181     strncpy(ccid, replybuffer, 20);
00182     ccid[20] = 0;
00183     
00184     readline(); // eat 'OK'
00185     
00186     return strlen(ccid);
00187 }
00188 
00189 /********* IMEI **********************************************************/
00190 
00191 uint8_t Adafruit_FONA::getIMEI(char *imei) {
00192     getReply("AT+GSN");
00193     
00194     // up to 15 chars
00195     strncpy(imei, replybuffer, 15);
00196     imei[15] = 0;
00197     
00198     readline(); // eat 'OK'
00199     
00200     return strlen(imei);
00201 }
00202 
00203 /********* NETWORK *******************************************************/
00204 
00205 uint8_t Adafruit_FONA::getNetworkStatus(void) {
00206     uint16_t status;
00207     
00208     if (! sendParseReply("AT+CREG?", "+CREG: ", &status, ',', 1)) return 0;
00209     
00210     return status;
00211 }
00212 
00213 uint8_t Adafruit_FONA::setNetworkRoaming() {
00214     
00215     if (!sendCheckReply("AT+CREG=5", "OK", 10000)) return -1;
00216     
00217     return 1;
00218        
00219 }
00220 
00221 uint8_t Adafruit_FONA::getRSSI(void) {
00222     uint16_t reply;
00223     
00224     if (! sendParseReply("AT+CSQ", "+CSQ: ", &reply) ) return 0;
00225     
00226     return reply;
00227 }
00228 
00229 /********* AUDIO *******************************************************/
00230 
00231 bool Adafruit_FONA::setAudio(uint8_t a) {
00232     // 0 is headset, 1 is external audio
00233     if (a > 1) return false;
00234     
00235     return sendCheckReply("AT+CHFA=", a, "OK");
00236 }
00237 
00238 uint8_t Adafruit_FONA::getVolume(void) {
00239     uint16_t reply;
00240     
00241     if (! sendParseReply("AT+CLVL?", "+CLVL: ", &reply) ) return 0;
00242     
00243     return reply;
00244 }
00245 
00246 bool Adafruit_FONA::setVolume(uint8_t i) {
00247     return sendCheckReply("AT+CLVL=", i, "OK");
00248 }
00249 
00250 
00251 bool Adafruit_FONA::playDTMF(char dtmf) {
00252     char str[4];
00253     str[0] = '\"';
00254     str[1] = dtmf;
00255     str[2] = '\"';
00256     str[3] = 0;
00257     return sendCheckReply("AT+CLDTMF=3,", str, "OK");
00258 }
00259 
00260 bool Adafruit_FONA::playToolkitTone(uint8_t t, uint16_t len) {
00261     return sendCheckReply("AT+STTONE=1,", t, len, "OK");
00262 }
00263 
00264 bool Adafruit_FONA::setMicVolume(uint8_t a, uint8_t level) {
00265     // 0 is headset, 1 is external audio
00266     if (a > 1) return false;
00267     
00268     return sendCheckReply("AT+CMIC=", a, level, "OK");
00269 }
00270 
00271 /********* FM RADIO *******************************************************/
00272 
00273 
00274 bool Adafruit_FONA::FMradio(bool onoff, uint8_t a) {
00275     if (! onoff) {
00276         return sendCheckReply("AT+FMCLOSE", "OK");
00277     }
00278     
00279     // 0 is headset, 1 is external audio
00280     if (a > 1) return false;
00281     
00282     return sendCheckReply("AT+FMOPEN=", a, "OK");
00283 }
00284 
00285 bool Adafruit_FONA::tuneFMradio(uint16_t station) {
00286     // Fail if FM station is outside allowed range.
00287     if ((station < 870) || (station > 1090))
00288         return false;
00289     
00290     return sendCheckReply("AT+FMFREQ=", station, "OK");
00291 }
00292 
00293 bool Adafruit_FONA::setFMVolume(uint8_t i) {
00294     // Fail if volume is outside allowed range (0-6).
00295     if (i > 6) {
00296     return false;
00297     }
00298     // Send FM volume command and verify response.
00299     return sendCheckReply("AT+FMVOLUME=", i, "OK");
00300 }
00301 
00302 int8_t Adafruit_FONA::getFMVolume() {
00303     uint16_t level;
00304     
00305     if (! sendParseReply("AT+FMVOLUME?", "+FMVOLUME: ", &level) ) return 0;
00306     
00307     return level;
00308 }
00309 
00310 int8_t Adafruit_FONA::getFMSignalLevel(uint16_t station) {
00311     // Fail if FM station is outside allowed range.
00312     if ((station < 875) || (station > 1080)) {
00313         return -1;
00314     }   
00315     
00316     // Send FM signal level query command.
00317     // Note, need to explicitly send timeout so right overload is chosen.
00318     getReply("AT+FMSIGNAL=", station, FONA_DEFAULT_TIMEOUT_MS);
00319     // Check response starts with expected value.
00320     char *p = strstr(replybuffer, "+FMSIGNAL: ");
00321     if (p == 0) return -1;
00322     p+=11;
00323     // Find second colon to get start of signal quality.
00324     p = strchr(p, ':');
00325     if (p == 0) return -1;
00326     p+=1;
00327     // Parse signal quality.
00328     int8_t level = atoi(p);
00329     readline();  // eat the "OK"
00330     return level;
00331 }
00332 
00333 /********* PWM/BUZZER **************************************************/
00334 
00335 bool Adafruit_FONA::setPWM(uint16_t period, uint8_t duty) {
00336     if (period > 2000) return false;
00337     if (duty > 100) return false;
00338     
00339     return sendCheckReply("AT+SPWM=0,", period, duty, "OK");
00340 }
00341 
00342 /********* CALL PHONES **************************************************/
00343 bool Adafruit_FONA::callPhone(char *number) {
00344     char sendbuff[35] = "ATD";
00345     strncpy(sendbuff+3, number, min((int)30, (int)strlen(number)));
00346     uint8_t x = strlen(sendbuff);
00347     sendbuff[x] = ';';
00348     sendbuff[x+1] = 0;
00349     
00350     return sendCheckReply(sendbuff, "OK");
00351 }
00352 
00353 bool Adafruit_FONA::hangUp(void) {
00354     return sendCheckReply("ATH0", "OK");
00355 }
00356 
00357 bool Adafruit_FONA::pickUp(void) {
00358     return sendCheckReply("ATA", "OK");
00359 }
00360 
00361 void Adafruit_FONA::onIncomingCall() {
00362 #ifdef ADAFRUIT_FONA_DEBUG
00363     printf("> Incoming call...\r\n");
00364 #endif
00365     _incomingCall = true;
00366 }
00367 
00368 bool Adafruit_FONA::callerIdNotification(bool enable) {
00369     if(enable){
00370         _ringIndicatorInterruptIn.fall(this, &Adafruit_FONA::onIncomingCall);
00371         return sendCheckReply("AT+CLIP=1", "OK");
00372     }
00373     
00374     _ringIndicatorInterruptIn.fall(NULL);
00375     return sendCheckReply("AT+CLIP=0", "OK");
00376 }
00377 
00378 bool Adafruit_FONA::incomingCallNumber(char* phonenum) {
00379     //+CLIP: "<incoming phone number>",145,"",0,"",0
00380     if(!_incomingCall)
00381         return false;
00382     
00383     readline();
00384     while(!strcmp(replybuffer, "RING") == 0) {
00385         flushInput();
00386         readline();
00387     }
00388     
00389     readline(); //reads incoming phone number line
00390     
00391     parseReply("+CLIP: \"", phonenum, '"');
00392     
00393 #ifdef ADAFRUIT_FONA_DEBUG
00394     printf("Phone Number: %s\r\n", replybuffer);
00395 #endif
00396     
00397     _incomingCall = false;
00398     return true;
00399 }
00400 
00401 /********* SMS **********************************************************/
00402 
00403 uint8_t Adafruit_FONA::getSMSInterrupt(void) {
00404     uint16_t reply;
00405     
00406     if (! sendParseReply("AT+CFGRI?", "+CFGRI: ", &reply) ) return 0;
00407     
00408     return reply;
00409 }
00410 
00411 bool Adafruit_FONA::setSMSInterrupt(uint8_t i) {
00412     return sendCheckReply("AT+CFGRI=", i, "OK");
00413 }
00414 
00415 int8_t Adafruit_FONA::getNumSMS(void) {
00416     uint16_t numsms;
00417     
00418     if (! sendCheckReply("AT+CMGF=1", "OK")) return -1;
00419     // ask how many sms are stored
00420     
00421     if (! sendParseReply("AT+CPMS?", "+CPMS: \"SM_P\",", &numsms) ) return -1;
00422     
00423     return numsms;
00424 }
00425 
00426 // Reading SMS's is a bit involved so we don't use helpers that may cause delays or debug
00427 // printouts!
00428 bool Adafruit_FONA::readSMS(uint8_t i, char *smsbuff, uint16_t maxlen, uint16_t *readlen) {
00429     // text mode
00430     if (! sendCheckReply("AT+CMGF=1", "OK")) return false;
00431     
00432     // show all text mode parameters
00433     if (! sendCheckReply("AT+CSDH=1", "OK")) return false;
00434     
00435     // parse out the SMS len
00436     uint16_t thesmslen = 0;
00437     
00438     //getReply(F("AT+CMGR="), i, 1000);  //  do not print debug!
00439     mySerial.printf("AT+CMGR=%d\r\n", i);
00440     readline(1000); // timeout
00441     
00442     // parse it out...
00443     if (! parseReply("+CMGR:", &thesmslen, ',', 11)) {
00444         *readlen = 0;
00445         return false;
00446     }
00447     
00448     readRaw(thesmslen);
00449     
00450     flushInput();
00451     
00452     uint16_t thelen = min(maxlen, (uint16_t)strlen(replybuffer));
00453     strncpy(smsbuff, replybuffer, thelen);
00454     smsbuff[thelen] = 0; // end the string
00455     
00456 #ifdef ADAFRUIT_FONA_DEBUG
00457     printf("%s\r\n", replybuffer);
00458 #endif
00459     *readlen = thelen;
00460     return true;
00461 }
00462 
00463 // Retrieve the sender of the specified SMS message and copy it as a string to
00464 // the sender buffer.  Up to senderlen characters of the sender will be copied
00465 // and a null terminator will be added if less than senderlen charactesr are
00466 // copied to the result.  Returns true if a result was successfully retrieved,
00467 // otherwise false.
00468 bool Adafruit_FONA::getSMSSender(uint8_t i, char *sender, int senderlen) {
00469     // Ensure text mode and all text mode parameters are sent.
00470     if (! sendCheckReply("AT+CMGF=1", "OK")) return false;
00471     if (! sendCheckReply("AT+CSDH=1", "OK")) return false;
00472     // Send command to retrieve SMS message and parse a line of response.
00473     mySerial.printf("AT+CMGR=%d\r\n", i);
00474     readline(1000);
00475     // Parse the second field in the response.
00476     bool result = parseReplyQuoted("+CMGR:", sender, senderlen, ',', 1);
00477     // Drop any remaining data from the response.
00478     flushInput();
00479     return result;
00480 }
00481 
00482 bool Adafruit_FONA::sendSMS(char *smsaddr, char *smsmsg) {
00483     if (! sendCheckReply("AT+CMGF=1", "OK")) return -1;
00484     
00485     char sendcmd[30] = "AT+CMGS=\"";
00486     strncpy(sendcmd+9, smsaddr, 30-9-2);  // 9 bytes beginning, 2 bytes for close quote + null
00487     sendcmd[strlen(sendcmd)] = '\"';
00488     
00489     if (! sendCheckReply(sendcmd, "> ")) return false;
00490 #ifdef ADAFRUIT_FONA_DEBUG
00491     printf("> %s\r\n", smsmsg);
00492 #endif
00493     mySerial.printf("%s\r\n\r\n", smsmsg);
00494     mySerial.putc(0x1A);
00495 #ifdef ADAFRUIT_FONA_DEBUG
00496     printf("^Z\r\n");
00497 #endif
00498     readline(10000); // read the +CMGS reply, wait up to 10 seconds!!!
00499     //Serial.print("* "); Serial.println(replybuffer);
00500     if (strstr(replybuffer, "+CMGS") == 0) {
00501         return false;
00502     }
00503     readline(1000); // read OK
00504     //Serial.print("* "); Serial.println(replybuffer);
00505     
00506     if (strcmp(replybuffer, "OK") != 0) {
00507         return false;
00508     }
00509     
00510     return true;
00511 }
00512 
00513 
00514 bool Adafruit_FONA::deleteSMS(uint8_t i) {
00515     if (! sendCheckReply("AT+CMGF=1", "OK")) return -1;
00516     // read an sms
00517     char sendbuff[12] = "AT+CMGD=000";
00518     sendbuff[8] = (i / 100) + '0';
00519     i %= 100;
00520     sendbuff[9] = (i / 10) + '0';
00521     i %= 10;
00522     sendbuff[10] = i + '0';
00523     
00524     return sendCheckReply(sendbuff, "OK", 2000);
00525 }
00526 
00527 /********* TIME **********************************************************/
00528 
00529 bool Adafruit_FONA::enableNetworkTimeSync(bool onoff) {
00530     if (onoff) {
00531         if (! sendCheckReply("AT+CLTS=1", "OK"))
00532             return false;
00533     } else {
00534         if (! sendCheckReply("AT+CLTS=0", "OK"))
00535             return false;
00536     }
00537     
00538     flushInput(); // eat any 'Unsolicted Result Code'
00539     
00540     return true;
00541 }
00542 
00543 bool Adafruit_FONA::enableNTPTimeSync(bool onoff, const char* ntpserver) {
00544     if (onoff) {
00545         if (! sendCheckReply("AT+CNTPCID=1", "OK"))
00546             return false;
00547         
00548         mySerial.printf("AT+CNTP=\"");
00549         if (ntpserver != 0) {
00550             mySerial.printf(ntpserver);
00551         } else {
00552             mySerial.printf("pool.ntp.org");
00553         }
00554         mySerial.printf("\",0\r\n");
00555         readline(FONA_DEFAULT_TIMEOUT_MS);
00556         if (strcmp(replybuffer, "OK") != 0)
00557             return false;
00558         
00559         if (! sendCheckReply("AT+CNTP", "OK", 10000))
00560             return false;
00561         
00562         uint16_t status;
00563         readline(10000);
00564         if (! parseReply("+CNTP:", &status))
00565             return false;
00566     } else {
00567         if (! sendCheckReply("AT+CNTPCID=0", "OK"))
00568             return false;
00569     }
00570     
00571     return true;
00572 }
00573 
00574 bool Adafruit_FONA::getTime(char* buff, uint16_t maxlen) {
00575     getReply("AT+CCLK?", (uint16_t) 10000);
00576     if (strncmp(replybuffer, "+CCLK: ", 7) != 0)
00577         return false;
00578     
00579     char *p = replybuffer+7;
00580     uint16_t lentocopy = min((uint16_t)(maxlen-1), (uint16_t)strlen(p));
00581     strncpy(buff, p, lentocopy+1);
00582     buff[lentocopy] = 0;
00583     
00584     readline(); // eat OK
00585     
00586     return true;
00587 }
00588 
00589 /********* GPS **********************************************************/
00590 
00591 
00592 bool Adafruit_FONA::enableGPS(bool onoff) {
00593     uint16_t state;
00594     
00595     // first check if its already on or off
00596     if (! sendParseReply("AT+CGPSPWR?", "+CGPSPWR: ", &state) )
00597         return false;
00598     
00599     if (onoff && !state) {
00600         if (! sendCheckReply("AT+CGPSPWR=1", "OK"))
00601             return false;
00602     } else if (!onoff && state) {
00603         if (! sendCheckReply("AT+CGPSPWR=0", "OK"))
00604             return false;
00605     }
00606     return true;
00607 }
00608 
00609 int8_t Adafruit_FONA::GPSstatus(void) {
00610     getReply("AT+CGPSSTATUS?");
00611     
00612     char *p = strstr(replybuffer, "+CGPSSTATUS: Location ");
00613     if (p == 0) return -1;
00614     
00615     p+=22;
00616     
00617     readline(); // eat 'OK'
00618     
00619     
00620     if (p[0] == 'U') return 0;
00621     if (p[0] == 'N') return 1;
00622     if (p[0] == '2') return 2;
00623     if (p[0] == '3') return 3;
00624     
00625     // else
00626     return 0;
00627 }
00628 
00629 uint8_t Adafruit_FONA::getGPS(uint8_t arg, char *buffer, uint8_t maxbuff) {
00630     int32_t x = arg;
00631     
00632     getReply("AT+CGPSINF=", x);
00633     
00634     char *p = strstr(replybuffer, "CGPSINF: ");
00635     if (p == 0){
00636         buffer[0] = 0;
00637         return 0;
00638     }
00639     p+=9;
00640     uint8_t len = max((uint8_t)(maxbuff-1), (uint8_t)strlen(p));
00641     strncpy(buffer, p, len);
00642     buffer[len] = 0;
00643     
00644     readline(); // eat 'OK'
00645     return len;
00646 }
00647 
00648 bool Adafruit_FONA::getGPS(float *lat, float *lon, float *speed_kph, float *heading, float *altitude) {
00649     char gpsbuffer[120];
00650     
00651     // we need at least a 2D fix
00652     if (GPSstatus() < 2)
00653         return false;
00654     
00655     // grab the mode 2^5 gps csv from the sim808
00656     uint8_t res_len = getGPS(32, gpsbuffer, 120);
00657     
00658     // make sure we have a response
00659     if (res_len == 0)
00660         return false;
00661     
00662     // skip mode
00663     char *tok = strtok(gpsbuffer, ",");
00664     if (! tok) return false;
00665     
00666     // skip date
00667     tok = strtok(NULL, ",");
00668     if (! tok) return false;
00669     
00670     // skip fix
00671     tok = strtok(NULL, ",");
00672     if (! tok) return false;
00673     
00674     // grab the latitude
00675     char *latp = strtok(NULL, ",");
00676     if (! latp) return false;
00677     
00678     // grab latitude direction
00679     char *latdir = strtok(NULL, ",");
00680     if (! latdir) return false;
00681     
00682     // grab longitude
00683     char *longp = strtok(NULL, ",");
00684     if (! longp) return false;
00685     
00686     // grab longitude direction
00687     char *longdir = strtok(NULL, ",");
00688     if (! longdir) return false;
00689     
00690     double latitude = atof(latp);
00691     double longitude = atof(longp);
00692     
00693     // convert latitude from minutes to decimal
00694     float degrees = floor(latitude / 100);
00695     double minutes = latitude - (100 * degrees);
00696     minutes /= 60;
00697     degrees += minutes;
00698     
00699     // turn direction into + or -
00700     if (latdir[0] == 'S') degrees *= -1;
00701     
00702     *lat = degrees;
00703     
00704     // convert longitude from minutes to decimal
00705     degrees = floor(longitude / 100);
00706     minutes = longitude - (100 * degrees);
00707     minutes /= 60;
00708     degrees += minutes;
00709     
00710     // turn direction into + or -
00711     if (longdir[0] == 'W') degrees *= -1;
00712     
00713     *lon = degrees;
00714     
00715     // only grab speed if needed
00716     if (speed_kph != NULL) {
00717         
00718         // grab the speed in knots
00719         char *speedp = strtok(NULL, ",");
00720         if (! speedp) return false;
00721         
00722         // convert to kph
00723         *speed_kph = atof(speedp) * 1.852;
00724         
00725     }
00726     
00727     // only grab heading if needed
00728     if (heading != NULL) {
00729         
00730         // grab the speed in knots
00731         char *coursep = strtok(NULL, ",");
00732         if (! coursep) return false;
00733         
00734         *heading = atof(coursep);
00735     
00736     }
00737     
00738     // no need to continue
00739     if (altitude == NULL)
00740         return true;
00741     
00742     // we need at least a 3D fix for altitude
00743     if (GPSstatus() < 3)
00744         return false;
00745     
00746     // grab the mode 0 gps csv from the sim808
00747     res_len = getGPS(0, gpsbuffer, 120);
00748     
00749     // make sure we have a response
00750     if (res_len == 0)
00751         return false;
00752     
00753     // skip mode
00754     tok = strtok(gpsbuffer, ",");
00755     if (! tok) return false;
00756     
00757     // skip lat
00758     tok = strtok(NULL, ",");
00759     if (! tok) return false;
00760     
00761     // skip long
00762     tok = strtok(NULL, ",");
00763     if (! tok) return false;
00764     
00765     // grab altitude
00766     char *altp = strtok(NULL, ",");
00767     if (! altp) return false;
00768     
00769     *altitude = atof(altp);
00770     
00771     return true;
00772 }
00773 
00774 bool Adafruit_FONA::enableGPSNMEA(uint8_t i) {
00775     char sendbuff[15] = "AT+CGPSOUT=000";
00776     sendbuff[11] = (i / 100) + '0';
00777     i %= 100;
00778     sendbuff[12] = (i / 10) + '0';
00779     i %= 10;
00780     sendbuff[13] = i + '0';
00781     
00782     return sendCheckReply(sendbuff, "OK", 2000);
00783 }
00784 
00785 
00786 /********* GPRS **********************************************************/
00787 
00788 
00789 bool Adafruit_FONA::enableGPRS(bool onoff) {
00790     if (onoff) {
00791         // disconnect all sockets
00792         sendCheckReply("AT+CIPSHUT", "SHUT OK", 5000);
00793         
00794         if (! sendCheckReply("AT+CGATT=1", "OK", 10000))
00795             return false;
00796         
00797         // set bearer profile! connection type GPRS
00798         if (! sendCheckReply("AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"", "OK", 10000))
00799             return false;
00800         
00801         // set bearer profile access point name
00802         if (apn) {
00803             // Send command AT+SAPBR=3,1,"APN","<apn value>" where <apn value> is the configured APN value.
00804             if (! sendCheckReplyQuoted("AT+SAPBR=3,1,\"APN\",", apn, "OK", 10000))
00805                 return false;
00806             
00807             // set username/password
00808             if (apnusername) {
00809                 // Send command AT+SAPBR=3,1,"USER","<user>" where <user> is the configured APN username.
00810                 if (! sendCheckReplyQuoted("AT+SAPBR=3,1,\"USER\",", apnusername, "OK", 10000))
00811                     return false;
00812             }
00813             if (apnpassword) {
00814                 // Send command AT+SAPBR=3,1,"PWD","<password>" where <password> is the configured APN password.
00815                 if (! sendCheckReplyQuoted("AT+SAPBR=3,1,\"PWD\",", apnpassword, "OK", 10000))
00816                     return false;
00817             }
00818         }
00819         
00820         // open GPRS context
00821         if (! sendCheckReply("AT+SAPBR=1,1", "OK", 10000))
00822             return false;
00823     } else {
00824         // disconnect all sockets
00825         if (! sendCheckReply("AT+CIPSHUT", "SHUT OK", 5000))
00826             return false;
00827         
00828         // close GPRS context
00829         if (! sendCheckReply("AT+SAPBR=0,1", "OK", 10000))
00830             return false;
00831         
00832         if (! sendCheckReply("AT+CGATT=0", "OK", 10000))
00833             return false;
00834     }
00835     return true;
00836 }
00837 
00838 uint8_t Adafruit_FONA::GPRSstate(void) {
00839     uint16_t state;
00840     
00841     if (! sendParseReply("AT+CGATT?", "+CGATT: ", &state) )
00842         return -1;
00843     
00844     return state;
00845 }
00846 
00847 void Adafruit_FONA::setGPRSNetworkSettings(const char* apn, const char* ausername, const char* apassword) {
00848     this->apn = (char*) apn;
00849     this->apnusername = (char*) ausername;
00850     this->apnpassword = (char*) apassword;
00851 }
00852 
00853 bool Adafruit_FONA::getGSMLoc(uint16_t *errorcode, char *buff, uint16_t maxlen) {
00854     getReply("AT+CIPGSMLOC=1,1", (uint16_t)10000);
00855     
00856     if (! parseReply("+CIPGSMLOC: ", errorcode))
00857         return false;
00858     
00859     char *p = replybuffer+14;
00860     uint16_t lentocopy = min((uint16_t)(maxlen-1), (uint16_t)strlen(p));
00861     strncpy(buff, p, lentocopy+1);
00862     
00863     readline(); // eat OK
00864     
00865     return true;
00866 }
00867 
00868 bool Adafruit_FONA::getGSMLoc(float *lat, float *lon) {
00869     uint16_t returncode;
00870     char gpsbuffer[120];
00871     
00872     // make sure we could get a response
00873     if (! getGSMLoc(&returncode, gpsbuffer, 120))
00874         return false;
00875     
00876     // make sure we have a valid return code
00877     if (returncode != 0)
00878         return false;
00879     
00880     // tokenize the gps buffer to locate the lat & long
00881     char *latp = strtok(gpsbuffer, ",");
00882     if (! latp) return false;
00883     
00884     char *longp = strtok(NULL, ",");
00885     if (! longp) return false;
00886     
00887     *lat = atof(latp);
00888     *lon = atof(longp);
00889     
00890     return true;
00891 }
00892 
00893 /********* TCP FUNCTIONS  ************************************/
00894 
00895 
00896 bool Adafruit_FONA::TCPconnect(char *server, uint16_t port) {
00897     flushInput();
00898     
00899     // close all old connections
00900     if (! sendCheckReply("AT+CIPSHUT", "SHUT OK", 5000) ) return false;
00901     
00902     // single connection at a time
00903     if (! sendCheckReply("AT+CIPMUX=0", "OK") ) return false;
00904     
00905     // manually read data
00906     if (! sendCheckReply("AT+CIPRXGET=1", "OK") ) return false;
00907     
00908 #ifdef ADAFRUIT_FONA_DEBUG
00909     printf("AT+CIPSTART=\"TCP\",\"%s\",\"%d\"\r\n", server, port);
00910 #endif
00911     
00912     mySerial.printf("AT+CIPSTART=\"TCP\",\"%s\",\"%d\"\r\n", server, port);
00913     
00914     if (! expectReply("OK")) return false;
00915     if (! expectReply("CONNECT OK")) return false;
00916     return true;
00917 }
00918 
00919 bool Adafruit_FONA::TCPclose(void) {
00920     return sendCheckReply("AT+CIPCLOSE", "OK");
00921 }
00922 
00923 bool Adafruit_FONA::TCPconnected(void) {
00924     if (! sendCheckReply("AT+CIPSTATUS", "OK", 100) ) return false;
00925     readline(100);
00926 #ifdef ADAFRUIT_FONA_DEBUG
00927     printf("\t<--- %s\r\n", replybuffer);
00928 #endif
00929     return (strcmp(replybuffer, "STATE: CONNECT OK") == 0);
00930 }
00931 
00932 bool Adafruit_FONA::TCPsend(char *packet, uint8_t len) {
00933 #ifdef ADAFRUIT_FONA_DEBUG
00934     printf("AT+CIPSEND=%d\r\n", len);
00935     
00936     for (uint16_t i=0; i<len; i++) {
00937         printf(" 0x%#02x", packet[i]);
00938     }
00939     printf("\r\n");
00940 #endif
00941     
00942     
00943     mySerial.printf("AT+CIPSEND=%d\r\n", len);
00944     readline();
00945 #ifdef ADAFRUIT_FONA_DEBUG
00946     printf("\t<--- %s\r\n", replybuffer);
00947 #endif
00948     if (replybuffer[0] != '>') return false;
00949     
00950     for (uint16_t i=0; i<len; i++) {
00951         mySerial.putc(packet[i]);
00952     }
00953     readline(3000); // wait up to 3 seconds to send the data
00954 #ifdef ADAFRUIT_FONA_DEBUG
00955     printf("\t<--- %s\r\n", replybuffer);
00956 #endif
00957     
00958     return (strcmp(replybuffer, "SEND OK") == 0);
00959 }
00960 
00961 uint16_t Adafruit_FONA::TCPavailable(void) {
00962     uint16_t avail;
00963     
00964     if (! sendParseReply("AT+CIPRXGET=4", "+CIPRXGET: 4,", &avail, ',', 0) ) return false;
00965     
00966 #ifdef ADAFRUIT_FONA_DEBUG
00967     printf("%d bytes available\r\n", avail);
00968 #endif
00969     
00970     return avail;
00971 }
00972 
00973 
00974 uint16_t Adafruit_FONA::TCPread(uint8_t *buff, uint8_t len) {
00975     uint16_t avail;
00976     
00977     mySerial.printf("AT+CIPRXGET=2,%d\r\n", len);
00978     readline();
00979     if (! parseReply("+CIPRXGET: 2,", &avail, ',', 0)) return false;
00980     
00981     readRaw(avail);
00982     
00983 #ifdef ADAFRUIT_FONA_DEBUG
00984     printf("%d bytes read\r\n", avail);
00985     for (uint8_t i=0;i<avail;i++) {
00986         printf(" 0x%#02x", replybuffer[i]);
00987     }
00988     printf("\r\n");
00989 #endif
00990     
00991     memcpy(buff, replybuffer, avail);
00992     
00993     return avail;
00994 }
00995 
00996 /********* HTTP LOW LEVEL FUNCTIONS  ************************************/
00997 
00998 bool Adafruit_FONA::HTTP_init() {
00999     return sendCheckReply("AT+HTTPINIT", "OK");
01000 }
01001 
01002 bool Adafruit_FONA::HTTP_term() {
01003     return sendCheckReply("AT+HTTPTERM", "OK");
01004 }
01005 
01006 void Adafruit_FONA::HTTP_para_start(const char* parameter, bool quoted) {
01007     flushInput();
01008     
01009 #ifdef ADAFRUIT_FONA_DEBUG
01010     printf("\t---> AT+HTTPPARA=\"%s\"\r\n", parameter);
01011 #endif
01012     
01013     mySerial.printf("AT+HTTPPARA=\"%s", parameter);
01014     if (quoted)
01015         mySerial.printf("\",\"");
01016     else
01017         mySerial.printf("\",");
01018 }
01019 
01020 bool Adafruit_FONA::HTTP_para_end(bool quoted) {
01021     if (quoted)
01022         mySerial.printf("\"\r\n");
01023     else
01024         mySerial.printf("\r\n");
01025     
01026     return expectReply("OK");
01027 }
01028 
01029 bool Adafruit_FONA::HTTP_para(const char* parameter, const char* value) {
01030     HTTP_para_start(parameter, true);
01031     mySerial.printf(value);
01032     return HTTP_para_end(true);
01033 }
01034 
01035 bool Adafruit_FONA::HTTP_para(const char* parameter, int32_t value) {
01036     HTTP_para_start(parameter, false);
01037     mySerial.printf("%d", value);
01038     return HTTP_para_end(false);
01039 }
01040 
01041 bool Adafruit_FONA::HTTP_data(uint32_t size, uint32_t maxTime) {
01042     flushInput();
01043     
01044 #ifdef ADAFRUIT_FONA_DEBUG
01045     printf("\t---> AT+HTTPDATA=%d,%d\r\n", size, maxTime);
01046 #endif
01047     
01048     mySerial.printf("AT+HTTPDATA=%d,%d\r\n", size, maxTime);
01049     
01050     return expectReply("DOWNLOAD");
01051 }
01052 
01053 bool Adafruit_FONA::HTTP_action(uint8_t method, uint16_t *status, uint16_t *datalen, int32_t timeout) {
01054     // Send request.
01055     if (! sendCheckReply("AT+HTTPACTION=", method, "OK"))
01056         return false;
01057     
01058     // Parse response status and size.
01059     readline(timeout);
01060     if (! parseReply("+HTTPACTION:", status, ',', 1))
01061         return false;
01062     if (! parseReply("+HTTPACTION:", datalen, ',', 2))
01063         return false;
01064     
01065     return true;
01066 }
01067 
01068 bool Adafruit_FONA::HTTP_readall(uint16_t *datalen) {
01069     getReply("AT+HTTPREAD");
01070     if (! parseReply("+HTTPREAD:", datalen, ',', 0))
01071         return false;
01072     
01073     return true;
01074 }
01075 
01076 bool Adafruit_FONA::HTTP_ssl(bool onoff) {
01077     return sendCheckReply("AT+HTTPSSL=", onoff ? 1 : 0, "OK");
01078 }
01079 
01080 /********* HTTP HIGH LEVEL FUNCTIONS ***************************/
01081 
01082 bool Adafruit_FONA::HTTP_GET_start(char *url, uint16_t *status, uint16_t *datalen){
01083     if (! HTTP_setup(url))
01084         return false;
01085     
01086     // HTTP GET
01087     if (! HTTP_action(FONA_HTTP_GET, status, datalen))
01088         return false;
01089     
01090 #ifdef ADAFRUIT_FONA_DEBUG
01091     printf("Status: %d\r\n", *status);
01092     printf("Len: %d\r\n", *datalen);
01093 #endif
01094     
01095     // HTTP response data
01096     if (! HTTP_readall(datalen))
01097         return false;
01098     
01099     return true;
01100 }
01101 
01102 void Adafruit_FONA::HTTP_GET_end(void) {
01103     HTTP_term();
01104 }
01105 
01106 bool Adafruit_FONA::HTTP_POST_start(char *url, const char* contenttype, const uint8_t *postdata, uint16_t postdatalen, uint16_t *status, uint16_t *datalen) {
01107     if (! HTTP_setup(url))
01108         return false;
01109     
01110     if (! HTTP_para("CONTENT", contenttype)) {
01111         return false;
01112     }
01113     
01114     // HTTP POST data
01115     if (! HTTP_data(postdatalen, 10000))
01116         return false;
01117     for (uint16_t i = 0; i < postdatalen; i++) {
01118         mySerial.putc(postdata[i]);
01119     }
01120     if (! expectReply("OK"))
01121         return false;
01122     
01123     // HTTP POST
01124     if (! HTTP_action(FONA_HTTP_POST, status, datalen))
01125         return false;
01126     
01127 #ifdef ADAFRUIT_FONA_DEBUG
01128     printf("Status: %d\r\n", *status);
01129     printf("Len: %d\r\n", *datalen);
01130 #endif
01131     
01132     // HTTP response data
01133     if (! HTTP_readall(datalen))
01134         return false;
01135     
01136     return true;
01137 }
01138 
01139 void Adafruit_FONA::HTTP_POST_end(void) {
01140     HTTP_term();
01141 }
01142 
01143 void Adafruit_FONA::setUserAgent(const char* useragent) {
01144     this->useragent = (char*) useragent;
01145 }
01146 
01147 void Adafruit_FONA::setHTTPSRedirect(bool onoff) {
01148     httpsredirect = onoff;
01149 }
01150 
01151 /********* HTTP HELPERS ****************************************/
01152 
01153 bool Adafruit_FONA::HTTP_setup(char *url) {
01154     // Handle any pending
01155     HTTP_term();
01156     
01157     // Initialize and set parameters
01158     if (! HTTP_init())
01159         return false;
01160     if (! HTTP_para("CID", 1))
01161         return false;
01162     if (! HTTP_para("UA", useragent))
01163         return false;
01164     if (! HTTP_para("URL", url))
01165         return false;
01166     
01167     // HTTPS redirect
01168     if (httpsredirect) {
01169         if (! HTTP_para("REDIR",1))
01170             return false;
01171         
01172         if (! HTTP_ssl(true))
01173             return false;
01174     }
01175     
01176     return true;
01177 }
01178 
01179 
01180 /********* HELPERS *********************************************/
01181 
01182 bool Adafruit_FONA::expectReply(const char* reply, uint16_t timeout) {
01183     readline(timeout);
01184 #ifdef ADAFRUIT_FONA_DEBUG
01185     printf("\t<--- %s\r\n", replybuffer);
01186 #endif
01187     return (strcmp(replybuffer, reply) == 0);
01188 }
01189 
01190 /********* LOW LEVEL *******************************************/
01191 
01192 void Adafruit_FONA::flushInput() {
01193     // Read all available serial input to flush pending data.
01194     uint16_t timeoutloop = 0;
01195     while (timeoutloop++ < 40) {
01196         while(readable()) {
01197             getc();
01198             timeoutloop = 0;  // If char was received reset the timer
01199         }
01200         Thread::wait(1);
01201     }
01202 }
01203 
01204 uint16_t Adafruit_FONA::readRaw(uint16_t b) {
01205     uint16_t idx = 0;
01206     
01207     while (b && (idx < sizeof(replybuffer)-1)) {
01208         if (readable()) {
01209             replybuffer[idx] = getc();
01210             idx++;
01211             b--;
01212         }
01213     }
01214     replybuffer[idx] = 0;
01215     
01216     return idx;
01217 }
01218 
01219 // This function just reads the output from FONA after an AT command is sent to it
01220 uint8_t Adafruit_FONA::readline(uint16_t timeout, bool multiline) {
01221     uint16_t replyidx = 0;
01222     
01223     while (timeout--) {
01224         if (replyidx >= 254) {
01225             break;
01226         }
01227     
01228         while(readable()) {
01229             char c =  getc();
01230             if (c == '\r') continue;
01231             if (c == 0xA) {
01232                 if (replyidx == 0)   // the first 0x0A is ignored
01233                     continue;
01234                 
01235                 if (!multiline) {
01236                     timeout = 0;         // the second 0x0A is the end of the line
01237                     break;
01238                 }
01239             }
01240             replybuffer[replyidx] = c;
01241             replyidx++;
01242         }
01243     
01244         if (timeout == 0) {
01245             break;
01246         }
01247         Thread::wait(1);
01248     }
01249     replybuffer[replyidx] = 0;  // null term
01250     return replyidx;
01251 }
01252 
01253 uint8_t Adafruit_FONA::getReply(const char* send, uint16_t timeout) {
01254     flushInput();
01255 
01256 #ifdef ADAFRUIT_FONA_DEBUG
01257     printf("\t---> %s\r\n", send);
01258 #endif
01259 
01260     mySerial.printf("%s\r\n",send);
01261 
01262     uint8_t l = readline(timeout);
01263 #ifdef ADAFRUIT_FONA_DEBUG
01264     printf("\t<--- %s\r\n", replybuffer);
01265 #endif
01266     return l;
01267 }
01268 
01269 // Send prefix, suffix, and newline. Return response (and also set replybuffer with response).
01270 uint8_t Adafruit_FONA::getReply(const char* prefix, char* suffix, uint16_t timeout) {
01271     flushInput();
01272     
01273 #ifdef ADAFRUIT_FONA_DEBUG
01274     printf("\t---> %s%s\r\n", prefix, suffix);
01275 #endif
01276     
01277     mySerial.printf("%s%s\r\n", prefix, suffix);
01278     
01279     uint8_t l = readline(timeout);
01280 #ifdef ADAFRUIT_FONA_DEBUG
01281     printf("\t<--- %s\r\n", replybuffer);
01282 #endif
01283     return l;
01284 }
01285 
01286 // Send prefix, suffix, and newline. Return response (and also set replybuffer with response).
01287 uint8_t Adafruit_FONA::getReply(const char* prefix, int32_t suffix, uint16_t timeout) {
01288     flushInput();
01289     
01290 #ifdef ADAFRUIT_FONA_DEBUG
01291     printf("\t---> %s%d\r\n", prefix, suffix);
01292 #endif
01293     
01294     mySerial.printf("%s%d\r\n", prefix, suffix);
01295     
01296     uint8_t l = readline(timeout);
01297 #ifdef ADAFRUIT_FONA_DEBUG
01298     printf("\t<--- %s\r\n", replybuffer);
01299 #endif
01300     return l;
01301 }
01302 
01303 // Send prefix, suffix, suffix2, and newline. Return response (and also set replybuffer with response).
01304 uint8_t Adafruit_FONA::getReply(const char* prefix, int32_t suffix1, int32_t suffix2, uint16_t timeout) {
01305     flushInput();
01306     
01307 #ifdef ADAFRUIT_FONA_DEBUG
01308     printf("\t---> %s%d,%d\r\n", prefix, suffix1, suffix2);
01309 #endif
01310     
01311     mySerial.printf("%s%d,%d\r\n", prefix, suffix1, suffix2);
01312     
01313     uint8_t l = readline(timeout);
01314 #ifdef ADAFRUIT_FONA_DEBUG
01315     printf("\t<--- %s\r\n", replybuffer);
01316 #endif
01317     return l;
01318 }
01319 
01320 // Send prefix, ", suffix, ", and newline. Return response (and also set replybuffer with response).
01321 uint8_t Adafruit_FONA::getReplyQuoted(const char* prefix, const char* suffix, uint16_t timeout) {
01322     flushInput();
01323     
01324 #ifdef ADAFRUIT_FONA_DEBUG
01325     printf("\t---> %s\"%s\"\r\n", prefix, suffix);
01326 #endif
01327     
01328     mySerial.printf("%s\"%s\"\r\n", prefix, suffix);
01329     
01330     uint8_t l = readline(timeout);
01331 #ifdef ADAFRUIT_FONA_DEBUG
01332     printf("\t<--- %s\r\n", replybuffer);
01333 #endif
01334     return l;
01335 }
01336 
01337 
01338 bool Adafruit_FONA::sendCheckReply(const char *send, const char *reply, uint16_t timeout) {
01339     getReply(send, timeout);
01340     
01341     return (strcmp(replybuffer, reply) == 0);
01342 }
01343 
01344 // Send prefix, suffix, and newline.  Verify FONA response matches reply parameter.
01345 bool Adafruit_FONA::sendCheckReply(const char* prefix, char *suffix, const char* reply, uint16_t timeout) {
01346     getReply(prefix, suffix, timeout);
01347     return (strcmp(replybuffer, reply) == 0);
01348 }
01349 
01350 // Send prefix, suffix, and newline.  Verify FONA response matches reply parameter.
01351 bool Adafruit_FONA::sendCheckReply(const char* prefix, int32_t suffix, const char* reply, uint16_t timeout) {
01352     getReply(prefix, suffix, timeout);
01353     return (strcmp(replybuffer, reply) == 0);
01354 }
01355 
01356 // Send prefix, suffix, suffix2, and newline.  Verify FONA response matches reply parameter.
01357 bool Adafruit_FONA::sendCheckReply(const char* prefix, int32_t suffix1, int32_t suffix2, const char* reply, uint16_t timeout) {
01358     getReply(prefix, suffix1, suffix2, timeout);
01359     return (strcmp(replybuffer, reply) == 0);
01360 }
01361 
01362 // Send prefix, ", suffix, ", and newline.  Verify FONA response matches reply parameter.
01363 bool Adafruit_FONA::sendCheckReplyQuoted(const char* prefix, const char* suffix, const char* reply, uint16_t timeout) {
01364   getReplyQuoted(prefix, suffix, timeout);
01365   return (strcmp(replybuffer, reply) == 0);
01366 }
01367 
01368 bool Adafruit_FONA::parseReply(const char* toreply, uint16_t *v, char divider, uint8_t index) {
01369     char *p = strstr(replybuffer, toreply);  // get the pointer to the voltage
01370     if (p == 0) return false;
01371     p += strlen(toreply);
01372     
01373     for (uint8_t i=0; i<index;i++) {
01374         // increment dividers
01375         p = strchr(p, divider);
01376         if (!p) return false;
01377         p++;
01378     }
01379     
01380     *v = atoi(p);
01381     
01382     return true;
01383 }
01384 
01385 bool Adafruit_FONA::parseReply(const char* toreply, char *v, char divider, uint8_t index) {
01386     uint8_t i=0;
01387     char *p = strstr(replybuffer, toreply);
01388     if (p == 0) return false;
01389     p+=strlen(toreply);
01390     
01391     for (i=0; i<index;i++) {
01392         // increment dividers
01393         p = strchr(p, divider);
01394         if (!p) return false;
01395         p++;
01396     }
01397     
01398     for(i=0; i<strlen(p);i++) {
01399         if(p[i] == divider)
01400             break;
01401         v[i] = p[i];
01402     }
01403     
01404     v[i] = '\0';
01405     
01406     return true;
01407 }
01408 
01409 // Parse a quoted string in the response fields and copy its value (without quotes)
01410 // to the specified character array (v).  Only up to maxlen characters are copied
01411 // into the result buffer, so make sure to pass a large enough buffer to handle the
01412 // response.
01413 bool Adafruit_FONA::parseReplyQuoted(const char* toreply, char* v, int maxlen, char divider, uint8_t index) {
01414     uint8_t i=0, j;
01415     // Verify response starts with toreply.
01416     char *p = strstr(replybuffer, toreply);
01417     if (p == 0) return false;
01418     p+=strlen(toreply);
01419     
01420     // Find location of desired response field.
01421     for (i=0; i<index;i++) {
01422         // increment dividers
01423         p = strchr(p, divider);
01424         if (!p) return false;
01425             p++;
01426     }
01427     
01428     // Copy characters from response field into result string.
01429     for(i=0, j=0; j<maxlen && i<strlen(p); ++i) {
01430         // Stop if a divier is found.
01431         if(p[i] == divider)
01432             break;
01433         // Skip any quotation marks.
01434         else if(p[i] == '"')
01435             continue;
01436         v[j++] = p[i];
01437     }
01438     
01439     // Add a null terminator if result string buffer was not filled.
01440     if (j < maxlen)
01441         v[j] = '\0';
01442     
01443     return true;
01444 }
01445 
01446 bool Adafruit_FONA::sendParseReply(const char* tosend, const char* toreply, uint16_t *v, char divider, uint8_t index) {
01447     getReply(tosend);
01448     
01449     if (! parseReply(toreply, v, divider, index)) return false;
01450     
01451     readline(); // eat 'OK'
01452     
01453     return true;
01454 }