Library for the Adafruit FONA. This is a port of the original Arduino library available at: https://github.com/adafruit/Adafruit_FONA_Library .

Dependents:   Adafruit_FONA_Library_FONAtest

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