Library For the Adafruit FONA 808

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     // next line per http://postwarrior.com/arduino-ethershield-error-prog_char-does-not-name-a-type/
00018 
00019 #include "Adafruit_FONA.h"
00020 
00021 
00022 
00023 
00024 Adafruit_FONA::Adafruit_FONA(int8_t rst)
00025 {
00026   _rstpin = rst;
00027 
00028   apn = F("FONAnet");
00029   apnusername = 0;
00030   apnpassword = 0;
00031   mySerial = 0;
00032   httpsredirect = false;
00033   useragent = F("FONA");
00034   ok_reply = F("OK");
00035 }
00036 
00037 uint8_t Adafruit_FONA::type(void) {
00038   return _type;
00039 }
00040 
00041 boolean Adafruit_FONA::begin(Stream &port) {
00042   mySerial = &port;
00043 
00044   pinMode(_rstpin, OUTPUT);
00045   digitalWrite(_rstpin, HIGH);
00046   delay(10);
00047   digitalWrite(_rstpin, LOW);
00048   delay(100);
00049   digitalWrite(_rstpin, HIGH);
00050 
00051   DEBUG_PRINTLN(F("Attempting to open comm with ATs"));
00052   // give 7 seconds to reboot
00053   int16_t timeout = 7000;
00054 
00055   while (timeout > 0) {
00056     while (mySerial->available()) mySerial->read();
00057     if (sendCheckReply(F("AT"), ok_reply))
00058       break;
00059     while (mySerial->available()) mySerial->read();
00060     if (sendCheckReply(F("AT"), F("AT"))) 
00061       break;
00062     delay(500);
00063     timeout-=500;
00064   }
00065 
00066   if (timeout <= 0) {
00067 #ifdef ADAFRUIT_FONA_DEBUG
00068     DEBUG_PRINTLN(F("Timeout: No response to AT... last ditch attempt."));
00069 #endif
00070     sendCheckReply(F("AT"), ok_reply);
00071     delay(100);
00072     sendCheckReply(F("AT"), ok_reply);
00073     delay(100);
00074     sendCheckReply(F("AT"), ok_reply);
00075     delay(100);
00076   }
00077 
00078   // turn off Echo!
00079   sendCheckReply(F("ATE0"), ok_reply);
00080   delay(100);
00081 
00082   if (! sendCheckReply(F("ATE0"), ok_reply)) {
00083     return false;
00084   }
00085 
00086   // turn on hangupitude
00087   sendCheckReply(F("AT+CVHU=0"), ok_reply);
00088 
00089   delay(100);
00090   flushInput();
00091 
00092 
00093   DEBUG_PRINT(F("\t---> ")); DEBUG_PRINTLN("ATI");
00094 
00095   mySerial->println("ATI");
00096   readline(500, true);
00097 
00098   DEBUG_PRINT (F("\t<--- ")); DEBUG_PRINTLN(replybuffer);
00099 
00100 
00101 
00102   if (prog_char_strstr(replybuffer, (prog_char *)F("SIM808 R14")) != 0) {
00103     _type = FONA808_V2;
00104   } else if (prog_char_strstr(replybuffer, (prog_char *)F("SIM808 R13")) != 0) {
00105     _type = FONA808_V1;
00106   } else if (prog_char_strstr(replybuffer, (prog_char *)F("SIM800 R13")) != 0) {
00107     _type = FONA800L;
00108   } else if (prog_char_strstr(replybuffer, (prog_char *)F("SIMCOM_SIM5320A")) != 0) {
00109     _type = FONA3G_A;
00110   } else if (prog_char_strstr(replybuffer, (prog_char *)F("SIMCOM_SIM5320E")) != 0) {
00111     _type = FONA3G_E;
00112   }
00113 
00114   if (_type == FONA800L) {
00115     // determine if L or H
00116 
00117   DEBUG_PRINT(F("\t---> ")); DEBUG_PRINTLN("AT+GMM");
00118 
00119     mySerial->println("AT+GMM");
00120     readline(500, true);
00121 
00122   DEBUG_PRINT (F("\t<--- ")); DEBUG_PRINTLN(replybuffer);
00123 
00124 
00125     if (prog_char_strstr(replybuffer, (prog_char *)F("SIM800H")) != 0) {
00126       _type = FONA800H;
00127     }
00128   }
00129 
00130 #if defined(FONA_PREF_SMS_STORAGE)
00131   sendCheckReply(F("AT+CPMS=\"" FONA_PREF_SMS_STORAGE "\""), ok_reply);
00132 #endif
00133 
00134   return true;
00135 }
00136 
00137 
00138 /********* Serial port ********************************************/
00139 boolean Adafruit_FONA::setBaudrate(uint16_t baud) {
00140   return sendCheckReply(F("AT+IPREX="), baud, ok_reply);
00141 }
00142 
00143 /********* Real Time Clock ********************************************/
00144 
00145 boolean Adafruit_FONA::readRTC(uint8_t *year, uint8_t *month, uint8_t *date, uint8_t *hr, uint8_t *min, uint8_t *sec) {
00146   uint16_t v;
00147   sendParseReply(F("AT+CCLK?"), F("+CCLK: "), &v, '/', 0);
00148   *year = v;
00149 
00150   DEBUG_PRINTLN(*year);
00151 }
00152 
00153 boolean Adafruit_FONA::enableRTC(uint8_t i) {
00154   if (! sendCheckReply(F("AT+CLTS="), i, ok_reply))
00155     return false;
00156   return sendCheckReply(F("AT&W"), ok_reply);
00157 }
00158 
00159 
00160 /********* BATTERY & ADC ********************************************/
00161 
00162 /* returns value in mV (uint16_t) */
00163 boolean Adafruit_FONA::getBattVoltage(uint16_t *v) {
00164   return sendParseReply(F("AT+CBC"), F("+CBC: "), v, ',', 2);
00165 }
00166 
00167 /* returns value in mV (uint16_t) */
00168 boolean Adafruit_FONA_3G::getBattVoltage(uint16_t *v) {
00169   float f;
00170   boolean b = sendParseReply(F("AT+CBC"), F("+CBC: "), &f, ',', 2);
00171   *v = f*1000;
00172   return b;
00173 }
00174 
00175 
00176 /* returns the percentage charge of battery as reported by sim800 */
00177 boolean Adafruit_FONA::getBattPercent(uint16_t *p) {
00178   return sendParseReply(F("AT+CBC"), F("+CBC: "), p, ',', 1);
00179 }
00180 
00181 boolean Adafruit_FONA::getADCVoltage(uint16_t *v) {
00182   return sendParseReply(F("AT+CADC?"), F("+CADC: 1,"), v);
00183 }
00184 
00185 /********* SIM ***********************************************************/
00186 
00187 uint8_t Adafruit_FONA::unlockSIM(char *pin)
00188 {
00189   char sendbuff[14] = "AT+CPIN=";
00190   sendbuff[8] = pin[0];
00191   sendbuff[9] = pin[1];
00192   sendbuff[10] = pin[2];
00193   sendbuff[11] = pin[3];
00194   sendbuff[12] = '\0';
00195 
00196   return sendCheckReply(sendbuff, ok_reply);
00197 }
00198 
00199 uint8_t Adafruit_FONA::getSIMCCID(char *ccid) {
00200   getReply(F("AT+CCID"));
00201   // up to 28 chars for reply, 20 char total ccid
00202   if (replybuffer[0] == '+') {
00203     // fona 3g?
00204     strncpy(ccid, replybuffer+8, 20);
00205   } else {
00206     // fona 800 or 800
00207     strncpy(ccid, replybuffer, 20);
00208   }
00209   ccid[20] = 0;
00210 
00211   readline(); // eat 'OK'
00212 
00213   return strlen(ccid);
00214 }
00215 
00216 /********* IMEI **********************************************************/
00217 
00218 uint8_t Adafruit_FONA::getIMEI(char *imei) {
00219   getReply(F("AT+GSN"));
00220 
00221   // up to 15 chars
00222   strncpy(imei, replybuffer, 15);
00223   imei[15] = 0;
00224 
00225   readline(); // eat 'OK'
00226 
00227   return strlen(imei);
00228 }
00229 
00230 /********* NETWORK *******************************************************/
00231 
00232 uint8_t Adafruit_FONA::getNetworkStatus(void) {
00233   uint16_t status;
00234 
00235   if (! sendParseReply(F("AT+CREG?"), F("+CREG: "), &status, ',', 1)) return 0;
00236 
00237   return status;
00238 }
00239 
00240 
00241 uint8_t Adafruit_FONA::getRSSI(void) {
00242   uint16_t reply;
00243 
00244   if (! sendParseReply(F("AT+CSQ"), F("+CSQ: "), &reply) ) return 0;
00245 
00246   return reply;
00247 }
00248 
00249 /********* AUDIO *******************************************************/
00250 
00251 boolean Adafruit_FONA::setAudio(uint8_t a) {
00252   // 0 is headset, 1 is external audio
00253   if (a > 1) return false;
00254 
00255   return sendCheckReply(F("AT+CHFA="), a, ok_reply);
00256 }
00257 
00258 uint8_t Adafruit_FONA::getVolume(void) {
00259   uint16_t reply;
00260 
00261   if (! sendParseReply(F("AT+CLVL?"), F("+CLVL: "), &reply) ) return 0;
00262 
00263   return reply;
00264 }
00265 
00266 boolean Adafruit_FONA::setVolume(uint8_t i) {
00267   return sendCheckReply(F("AT+CLVL="), i, ok_reply);
00268 }
00269 
00270 
00271 boolean Adafruit_FONA::playDTMF(char dtmf) {
00272   char str[4];
00273   str[0] = '\"';
00274   str[1] = dtmf;
00275   str[2] = '\"';
00276   str[3] = 0;
00277   return sendCheckReply(F("AT+CLDTMF=3,"), str, ok_reply);
00278 }
00279 
00280 boolean Adafruit_FONA::playToolkitTone(uint8_t t, uint16_t len) {
00281   return sendCheckReply(F("AT+STTONE=1,"), t, len, ok_reply);
00282 }
00283 
00284 boolean Adafruit_FONA_3G::playToolkitTone(uint8_t t, uint16_t len) {
00285   if (! sendCheckReply(F("AT+CPTONE="), t, ok_reply))
00286     return false;
00287   delay(len);
00288   return sendCheckReply(F("AT+CPTONE=0"), ok_reply);
00289 }
00290 
00291 boolean Adafruit_FONA::setMicVolume(uint8_t a, uint8_t level) {
00292   // 0 is headset, 1 is external audio
00293   if (a > 1) return false;
00294 
00295   return sendCheckReply(F("AT+CMIC="), a, level, ok_reply);
00296 }
00297 
00298 /********* FM RADIO *******************************************************/
00299 
00300 
00301 boolean Adafruit_FONA::FMradio(boolean onoff, uint8_t a) {
00302   if (! onoff) {
00303     return sendCheckReply(F("AT+FMCLOSE"), ok_reply);
00304   }
00305 
00306   // 0 is headset, 1 is external audio
00307   if (a > 1) return false;
00308 
00309   return sendCheckReply(F("AT+FMOPEN="), a, ok_reply);
00310 }
00311 
00312 boolean Adafruit_FONA::tuneFMradio(uint16_t station) {
00313   // Fail if FM station is outside allowed range.
00314   if ((station < 870) || (station > 1090))
00315     return false;
00316 
00317   return sendCheckReply(F("AT+FMFREQ="), station, ok_reply);
00318 }
00319 
00320 boolean Adafruit_FONA::setFMVolume(uint8_t i) {
00321   // Fail if volume is outside allowed range (0-6).
00322   if (i > 6) {
00323     return false;
00324   }
00325   // Send FM volume command and verify response.
00326   return sendCheckReply(F("AT+FMVOLUME="), i, ok_reply);
00327 }
00328 
00329 int8_t Adafruit_FONA::getFMVolume() {
00330   uint16_t level;
00331 
00332   if (! sendParseReply(F("AT+FMVOLUME?"), F("+FMVOLUME: "), &level) ) return 0;
00333 
00334   return level;
00335 }
00336 
00337 int8_t Adafruit_FONA::getFMSignalLevel(uint16_t station) {
00338   // Fail if FM station is outside allowed range.
00339   if ((station < 875) || (station > 1080)) {
00340     return -1;
00341   }
00342 
00343   // Send FM signal level query command.
00344   // Note, need to explicitly send timeout so right overload is chosen.
00345   getReply(F("AT+FMSIGNAL="), station, FONA_DEFAULT_TIMEOUT_MS);
00346   // Check response starts with expected value.
00347   char *p = prog_char_strstr(replybuffer, PSTR("+FMSIGNAL: "));
00348   if (p == 0) return -1;
00349   p+=11;
00350   // Find second colon to get start of signal quality.
00351   p = strchr(p, ':');
00352   if (p == 0) return -1;
00353   p+=1;
00354   // Parse signal quality.
00355   int8_t level = atoi(p);
00356   readline();  // eat the "OK"
00357   return level;
00358 }
00359 
00360 /********* PWM/BUZZER **************************************************/
00361 
00362 boolean Adafruit_FONA::setPWM(uint16_t period, uint8_t duty) {
00363   if (period > 2000) return false;
00364   if (duty > 100) return false;
00365 
00366   return sendCheckReply(F("AT+SPWM=0,"), period, duty, ok_reply);
00367 }
00368 
00369 /********* CALL PHONES **************************************************/
00370 boolean Adafruit_FONA::callPhone(char *number) {
00371   char sendbuff[35] = "ATD";
00372   strncpy(sendbuff+3, number, min(30, strlen(number)));
00373   uint8_t x = strlen(sendbuff);
00374   sendbuff[x] = ';';
00375   sendbuff[x+1] = 0;
00376   //DEBUG_PRINTLN(sendbuff);
00377 
00378   return sendCheckReply(sendbuff, ok_reply);
00379 }
00380 
00381 
00382 uint8_t Adafruit_FONA::getCallStatus(void) {
00383   uint16_t phoneStatus;
00384 
00385   if (! sendParseReply(F("AT+CPAS"), F("+CPAS: "), &phoneStatus)) 
00386     return FONA_CALL_FAILED; // 1, since 0 is actually a known, good reply
00387 
00388   return phoneStatus;  // 0 ready, 2 unkown, 3 ringing, 4 call in progress
00389 }
00390 
00391 boolean Adafruit_FONA::hangUp(void) {
00392   return sendCheckReply(F("ATH0"), ok_reply);
00393 }
00394 
00395 boolean Adafruit_FONA_3G::hangUp(void) {
00396   getReply(F("ATH"));
00397 
00398   return (prog_char_strstr(replybuffer, (prog_char *)F("VOICE CALL: END")) != 0);
00399 }
00400 
00401 boolean Adafruit_FONA::pickUp(void) {
00402   return sendCheckReply(F("ATA"), ok_reply);
00403 }
00404 
00405 boolean Adafruit_FONA_3G::pickUp(void) {
00406   return sendCheckReply(F("ATA"), F("VOICE CALL: BEGIN"));
00407 }
00408 
00409 
00410 void Adafruit_FONA::onIncomingCall() {
00411 
00412   DEBUG_PRINT(F("> ")); DEBUG_PRINTLN(F("Incoming call..."));
00413 
00414   Adafruit_FONA::_incomingCall = true;
00415 }
00416 
00417 boolean Adafruit_FONA::_incomingCall = false;
00418 
00419 boolean Adafruit_FONA::callerIdNotification(boolean enable, uint8_t interrupt) {
00420   if(enable){
00421     attachInterrupt(interrupt, onIncomingCall, FALLING);
00422     return sendCheckReply(F("AT+CLIP=1"), ok_reply);
00423   }
00424 
00425   detachInterrupt(interrupt);
00426   return sendCheckReply(F("AT+CLIP=0"), ok_reply);
00427 }
00428 
00429 boolean Adafruit_FONA::incomingCallNumber(char* phonenum) {
00430   //+CLIP: "<incoming phone number>",145,"",0,"",0
00431   if(!Adafruit_FONA::_incomingCall)
00432     return false;
00433 
00434   readline();
00435   while(!prog_char_strcmp(replybuffer, (prog_char*)F("RING")) == 0) {
00436     flushInput();
00437     readline();
00438   }
00439 
00440   readline(); //reads incoming phone number line
00441 
00442   parseReply(F("+CLIP: \""), phonenum, '"');
00443 
00444 
00445   DEBUG_PRINT(F("Phone Number: "));
00446   DEBUG_PRINTLN(replybuffer);
00447 
00448 
00449   Adafruit_FONA::_incomingCall = false;
00450   return true;
00451 }
00452 
00453 /********* SMS **********************************************************/
00454 
00455 uint8_t Adafruit_FONA::getSMSInterrupt(void) {
00456   uint16_t reply;
00457 
00458   if (! sendParseReply(F("AT+CFGRI?"), F("+CFGRI: "), &reply) ) return 0;
00459 
00460   return reply;
00461 }
00462 
00463 boolean Adafruit_FONA::setSMSInterrupt(uint8_t i) {
00464   return sendCheckReply(F("AT+CFGRI="), i, ok_reply);
00465 }
00466 
00467 int8_t Adafruit_FONA::getNumSMS(void) {
00468   uint16_t numsms;
00469 
00470   // get into text mode
00471   if (! sendCheckReply(F("AT+CMGF=1"), ok_reply)) return -1;
00472 
00473   // ask how many sms are stored
00474   if (sendParseReply(F("AT+CPMS?"), F("\"SM\","), &numsms)) 
00475     return numsms;
00476   if (sendParseReply(F("AT+CPMS?"), F("\"SM_P\","), &numsms)) 
00477     return numsms;
00478   return -1;
00479 }
00480 
00481 // Reading SMS's is a bit involved so we don't use helpers that may cause delays or debug
00482 // printouts!
00483 boolean Adafruit_FONA::readSMS(uint8_t i, char *smsbuff,
00484                    uint16_t maxlen, uint16_t *readlen) {
00485   // text mode
00486   if (! sendCheckReply(F("AT+CMGF=1"), ok_reply)) return false;
00487 
00488   // show all text mode parameters
00489   if (! sendCheckReply(F("AT+CSDH=1"), ok_reply)) return false;
00490 
00491   // parse out the SMS len
00492   uint16_t thesmslen = 0;
00493 
00494 
00495   DEBUG_PRINT(F("AT+CMGR="));
00496   DEBUG_PRINTLN(i);
00497 
00498 
00499   //getReply(F("AT+CMGR="), i, 1000);  //  do not print debug!
00500   mySerial->print(F("AT+CMGR="));
00501   mySerial->println(i);
00502   readline(1000); // timeout
00503 
00504   //DEBUG_PRINT(F("Reply: ")); DEBUG_PRINTLN(replybuffer);
00505   // parse it out...
00506 
00507 
00508   DEBUG_PRINTLN(replybuffer);
00509 
00510   
00511   if (! parseReply(F("+CMGR:"), &thesmslen, ',', 11)) {
00512     *readlen = 0;
00513     return false;
00514   }
00515 
00516   readRaw(thesmslen);
00517 
00518   flushInput();
00519 
00520   uint16_t thelen = min(maxlen, strlen(replybuffer));
00521   strncpy(smsbuff, replybuffer, thelen);
00522   smsbuff[thelen] = 0; // end the string
00523 
00524 
00525   DEBUG_PRINTLN(replybuffer);
00526 
00527   *readlen = thelen;
00528   return true;
00529 }
00530 
00531 // Retrieve the sender of the specified SMS message and copy it as a string to
00532 // the sender buffer.  Up to senderlen characters of the sender will be copied
00533 // and a null terminator will be added if less than senderlen charactesr are
00534 // copied to the result.  Returns true if a result was successfully retrieved,
00535 // otherwise false.
00536 boolean Adafruit_FONA::getSMSSender(uint8_t i, char *sender, int senderlen) {
00537   // Ensure text mode and all text mode parameters are sent.
00538   if (! sendCheckReply(F("AT+CMGF=1"), ok_reply)) return false;
00539   if (! sendCheckReply(F("AT+CSDH=1"), ok_reply)) return false;
00540 
00541 
00542   DEBUG_PRINT(F("AT+CMGR="));
00543   DEBUG_PRINTLN(i);
00544 
00545 
00546   // Send command to retrieve SMS message and parse a line of response.
00547   mySerial->print(F("AT+CMGR="));
00548   mySerial->println(i);
00549   readline(1000);
00550 
00551 
00552   DEBUG_PRINTLN(replybuffer);
00553 
00554 
00555   // Parse the second field in the response.
00556   boolean result = parseReplyQuoted(F("+CMGR:"), sender, senderlen, ',', 1);
00557   // Drop any remaining data from the response.
00558   flushInput();
00559   return result;
00560 }
00561 
00562 boolean Adafruit_FONA::sendSMS(char *smsaddr, char *smsmsg) {
00563   if (! sendCheckReply(F("AT+CMGF=1"), ok_reply)) return false;
00564 
00565   char sendcmd[30] = "AT+CMGS=\"";
00566   strncpy(sendcmd+9, smsaddr, 30-9-2);  // 9 bytes beginning, 2 bytes for close quote + null
00567   sendcmd[strlen(sendcmd)] = '\"';
00568 
00569   if (! sendCheckReply(sendcmd, F("> "))) return false;
00570 
00571   DEBUG_PRINT(F("> ")); DEBUG_PRINTLN(smsmsg);
00572 
00573   mySerial->println(smsmsg);
00574   mySerial->println();
00575   mySerial->write(0x1A);
00576 
00577   DEBUG_PRINTLN("^Z");
00578 
00579   if ( (_type == FONA3G_A) || (_type == FONA3G_E) ) {
00580     // Eat two sets of CRLF
00581     readline(200);
00582     //DEBUG_PRINT("Line 1: "); DEBUG_PRINTLN(strlen(replybuffer));
00583     readline(200);
00584     //DEBUG_PRINT("Line 2: "); DEBUG_PRINTLN(strlen(replybuffer));
00585   }
00586   readline(10000); // read the +CMGS reply, wait up to 10 seconds!!!
00587   //DEBUG_PRINT("Line 3: "); DEBUG_PRINTLN(strlen(replybuffer));
00588   if (strstr(replybuffer, "+CMGS") == 0) {
00589     return false;
00590   }
00591   readline(1000); // read OK
00592   //DEBUG_PRINT("* "); DEBUG_PRINTLN(replybuffer);
00593 
00594   if (strcmp(replybuffer, "OK") != 0) {
00595     return false;
00596   }
00597 
00598   return true;
00599 }
00600 
00601 
00602 boolean Adafruit_FONA::deleteSMS(uint8_t i) {
00603     if (! sendCheckReply(F("AT+CMGF=1"), ok_reply)) return false;
00604   // read an sms
00605   char sendbuff[12] = "AT+CMGD=000";
00606   sendbuff[8] = (i / 100) + '0';
00607   i %= 100;
00608   sendbuff[9] = (i / 10) + '0';
00609   i %= 10;
00610   sendbuff[10] = i + '0';
00611 
00612   return sendCheckReply(sendbuff, ok_reply, 2000);
00613 }
00614 
00615 /********* USSD *********************************************************/
00616 
00617 boolean Adafruit_FONA::sendUSSD(char *ussdmsg, char *ussdbuff, uint16_t maxlen, uint16_t *readlen) {
00618   if (! sendCheckReply(F("AT+CUSD=1"), ok_reply)) return false;
00619 
00620   char sendcmd[30] = "AT+CUSD=1,\"";
00621   strncpy(sendcmd+11, ussdmsg, 30-11-2);  // 11 bytes beginning, 2 bytes for close quote + null
00622   sendcmd[strlen(sendcmd)] = '\"';
00623 
00624   if (! sendCheckReply(sendcmd, ok_reply)) {
00625     *readlen = 0;
00626     return false;
00627   } else {
00628       readline(10000); // read the +CUSD reply, wait up to 10 seconds!!!
00629       //DEBUG_PRINT("* "); DEBUG_PRINTLN(replybuffer);
00630       char *p = prog_char_strstr(replybuffer, PSTR("+CUSD: "));
00631       if (p == 0) {
00632         *readlen = 0;
00633         return false;
00634       }
00635       p+=7; //+CUSD
00636       // Find " to get start of ussd message.
00637       p = strchr(p, '\"');
00638       if (p == 0) {
00639         *readlen = 0;
00640         return false;
00641       }
00642       p+=1; //"
00643       // Find " to get end of ussd message.
00644       char *strend = strchr(p, '\"');
00645 
00646       uint16_t lentocopy = min(maxlen-1, strend - p);
00647       strncpy(ussdbuff, p, lentocopy+1);
00648       ussdbuff[lentocopy] = 0;
00649       *readlen = lentocopy;
00650   }
00651   return true;
00652 }
00653 
00654 
00655 /********* TIME **********************************************************/
00656 
00657 boolean Adafruit_FONA::enableNetworkTimeSync(boolean onoff) {
00658   if (onoff) {
00659     if (! sendCheckReply(F("AT+CLTS=1"), ok_reply))
00660       return false;
00661   } else {
00662     if (! sendCheckReply(F("AT+CLTS=0"), ok_reply))
00663       return false;
00664   }
00665 
00666   flushInput(); // eat any 'Unsolicted Result Code'
00667 
00668   return true;
00669 }
00670 
00671 boolean Adafruit_FONA::enableNTPTimeSync(boolean onoff, FONAFlashStringPtr ntpserver) {
00672   if (onoff) {
00673     if (! sendCheckReply(F("AT+CNTPCID=1"), ok_reply))
00674       return false;
00675 
00676     mySerial->print(F("AT+CNTP=\""));
00677     if (ntpserver != 0) {
00678       mySerial->print(ntpserver);
00679     } else {
00680       mySerial->print(F("pool.ntp.org"));
00681     }
00682     mySerial->println(F("\",0"));
00683     readline(FONA_DEFAULT_TIMEOUT_MS);
00684     if (strcmp(replybuffer, "OK") != 0)
00685       return false;
00686 
00687     if (! sendCheckReply(F("AT+CNTP"), ok_reply, 10000))
00688       return false;
00689 
00690     uint16_t status;
00691     readline(10000);
00692     if (! parseReply(F("+CNTP:"), &status))
00693       return false;
00694   } else {
00695     if (! sendCheckReply(F("AT+CNTPCID=0"), ok_reply))
00696       return false;
00697   }
00698 
00699   return true;
00700 }
00701 
00702 boolean Adafruit_FONA::getTime(char *buff, uint16_t maxlen) {
00703   getReply(F("AT+CCLK?"), (uint16_t) 10000);
00704   if (strncmp(replybuffer, "+CCLK: ", 7) != 0)
00705     return false;
00706 
00707   char *p = replybuffer+7;
00708   uint16_t lentocopy = min(maxlen-1, strlen(p));
00709   strncpy(buff, p, lentocopy+1);
00710   buff[lentocopy] = 0;
00711 
00712   readline(); // eat OK
00713 
00714   return true;
00715 }
00716 
00717 /********* GPS **********************************************************/
00718 
00719 
00720 boolean Adafruit_FONA::enableGPS(boolean onoff) {
00721   uint16_t state;
00722 
00723   // first check if its already on or off
00724 
00725   if (_type == FONA808_V2) {
00726     if (! sendParseReply(F("AT+CGNSPWR?"), F("+CGNSPWR: "), &state) )
00727       return false;
00728   } else {
00729     if (! sendParseReply(F("AT+CGPSPWR?"), F("+CGPSPWR: "), &state))
00730       return false;
00731   }
00732 
00733   if (onoff && !state) {
00734     if (_type == FONA808_V2) {
00735       if (! sendCheckReply(F("AT+CGNSPWR=1"), ok_reply))  // try GNS command
00736     return false;
00737     } else {
00738       if (! sendCheckReply(F("AT+CGPSPWR=1"), ok_reply))
00739     return false;
00740     }
00741   } else if (!onoff && state) {
00742     if (_type == FONA808_V2) {
00743       if (! sendCheckReply(F("AT+CGNSPWR=0"), ok_reply)) // try GNS command
00744     return false;
00745     } else {
00746       if (! sendCheckReply(F("AT+CGPSPWR=0"), ok_reply))
00747     return false;
00748     }
00749   }
00750   return true;
00751 }
00752 
00753 
00754 
00755 boolean Adafruit_FONA_3G::enableGPS(boolean onoff) {
00756   uint16_t state;
00757 
00758   // first check if its already on or off
00759   if (! Adafruit_FONA::sendParseReply(F("AT+CGPS?"), F("+CGPS: "), &state) )
00760     return false;
00761 
00762   if (onoff && !state) {
00763     if (! sendCheckReply(F("AT+CGPS=1"), ok_reply))
00764       return false;
00765   } else if (!onoff && state) {
00766     if (! sendCheckReply(F("AT+CGPS=0"), ok_reply))
00767       return false;
00768     // this takes a little time
00769     readline(2000); // eat '+CGPS: 0'
00770   }
00771   return true;
00772 }
00773 
00774 int8_t Adafruit_FONA::GPSstatus(void) {
00775   if (_type == FONA808_V2) {
00776     // 808 V2 uses GNS commands and doesn't have an explicit 2D/3D fix status.
00777     // Instead just look for a fix and if found assume it's a 3D fix.
00778     getReply(F("AT+CGNSINF"));
00779     char *p = prog_char_strstr(replybuffer, (prog_char*)F("+CGNSINF: "));
00780     if (p == 0) return -1;
00781     p+=10;
00782     readline(); // eat 'OK'
00783     if (p[0] == '0') return 0; // GPS is not even on!
00784 
00785     p+=2; // Skip to second value, fix status.
00786     //DEBUG_PRINTLN(p);
00787     // Assume if the fix status is '1' then we have a 3D fix, otherwise no fix.
00788     if (p[0] == '1') return 3;
00789     else return 1;
00790   }
00791   if (_type == FONA3G_A || _type == FONA3G_E) {
00792     // FONA 3G doesn't have an explicit 2D/3D fix status.
00793     // Instead just look for a fix and if found assume it's a 3D fix.
00794     getReply(F("AT+CGPSINFO"));
00795     char *p = prog_char_strstr(replybuffer, (prog_char*)F("+CGPSINFO:"));
00796     if (p == 0) return -1;
00797     if (p[10] != ',') return 3; // if you get anything, its 3D fix
00798     return 0;
00799   }
00800   else {
00801     // 808 V1 looks for specific 2D or 3D fix state.
00802     getReply(F("AT+CGPSSTATUS?"));
00803     char *p = prog_char_strstr(replybuffer, (prog_char*)F("SSTATUS: Location "));
00804     if (p == 0) return -1;
00805     p+=18;
00806     readline(); // eat 'OK'
00807     //DEBUG_PRINTLN(p);
00808     if (p[0] == 'U') return 0;
00809     if (p[0] == 'N') return 1;
00810     if (p[0] == '2') return 2;
00811     if (p[0] == '3') return 3;
00812   }
00813   // else
00814   return 0;
00815 }
00816 
00817 uint8_t Adafruit_FONA::getGPS(uint8_t arg, char *buffer, uint8_t maxbuff) {
00818   int32_t x = arg;
00819 
00820   if ( (_type == FONA3G_A) || (_type == FONA3G_E) ) {
00821     getReply(F("AT+CGPSINFO"));
00822   } else if (_type == FONA808_V1) {
00823     getReply(F("AT+CGPSINF="), x);
00824   } else {
00825     getReply(F("AT+CGNSINF"));
00826   }
00827 
00828   char *p = prog_char_strstr(replybuffer, (prog_char*)F("SINF"));
00829   if (p == 0) {
00830     buffer[0] = 0;
00831     return 0;
00832   }
00833 
00834   p+=6;
00835 
00836   uint8_t len = max(maxbuff-1, strlen(p));
00837   strncpy(buffer, p, len);
00838   buffer[len] = 0;
00839 
00840   readline(); // eat 'OK'
00841   return len;
00842 }
00843 
00844 boolean Adafruit_FONA::getGPS(float *lat, float *lon, float *speed_kph, float *heading, float *altitude) {
00845 
00846   char gpsbuffer[120];
00847 
00848   // we need at least a 2D fix
00849   if (GPSstatus() < 2)
00850     return false;
00851 
00852   // grab the mode 2^5 gps csv from the sim808
00853   uint8_t res_len = getGPS(32, gpsbuffer, 120);
00854 
00855   // make sure we have a response
00856   if (res_len == 0)
00857     return false;
00858 
00859   if (_type == FONA3G_A || _type == FONA3G_E) {
00860     // Parse 3G respose
00861     // +CGPSINFO:4043.000000,N,07400.000000,W,151015,203802.1,-12.0,0.0,0
00862     // skip beginning
00863     char *tok;
00864 
00865    // grab the latitude
00866     char *latp = strtok(gpsbuffer, ",");
00867     if (! latp) return false;
00868 
00869     // grab latitude direction
00870     char *latdir = strtok(NULL, ",");
00871     if (! latdir) return false;
00872 
00873     // grab longitude
00874     char *longp = strtok(NULL, ",");
00875     if (! longp) return false;
00876 
00877     // grab longitude direction
00878     char *longdir = strtok(NULL, ",");
00879     if (! longdir) return false;
00880 
00881     // skip date & time
00882     tok = strtok(NULL, ",");
00883     tok = strtok(NULL, ",");
00884 
00885    // only grab altitude if needed
00886     if (altitude != NULL) {
00887       // grab altitude
00888       char *altp = strtok(NULL, ",");
00889       if (! altp) return false;
00890       *altitude = atof(altp);
00891     }
00892 
00893     // only grab speed if needed
00894     if (speed_kph != NULL) {
00895       // grab the speed in km/h
00896       char *speedp = strtok(NULL, ",");
00897       if (! speedp) return false;
00898 
00899       *speed_kph = atof(speedp);
00900     }
00901 
00902     // only grab heading if needed
00903     if (heading != NULL) {
00904 
00905       // grab the speed in knots
00906       char *coursep = strtok(NULL, ",");
00907       if (! coursep) return false;
00908 
00909       *heading = atof(coursep);
00910     }
00911 
00912     double latitude = atof(latp);
00913     double longitude = atof(longp);
00914 
00915     // convert latitude from minutes to decimal
00916     float degrees = floor(latitude / 100);
00917     double minutes = latitude - (100 * degrees);
00918     minutes /= 60;
00919     degrees += minutes;
00920 
00921     // turn direction into + or -
00922     if (latdir[0] == 'S') degrees *= -1;
00923 
00924     *lat = degrees;
00925 
00926     // convert longitude from minutes to decimal
00927     degrees = floor(longitude / 100);
00928     minutes = longitude - (100 * degrees);
00929     minutes /= 60;
00930     degrees += minutes;
00931 
00932     // turn direction into + or -
00933     if (longdir[0] == 'W') degrees *= -1;
00934 
00935     *lon = degrees;
00936 
00937   } else if (_type == FONA808_V2) {
00938     // Parse 808 V2 response.  See table 2-3 from here for format:
00939     // http://www.adafruit.com/datasheets/SIM800%20Series_GNSS_Application%20Note%20V1.00.pdf
00940 
00941     // skip GPS run status
00942     char *tok = strtok(gpsbuffer, ",");
00943     if (! tok) return false;
00944 
00945     // skip fix status
00946     tok = strtok(NULL, ",");
00947     if (! tok) return false;
00948 
00949     // skip date
00950     tok = strtok(NULL, ",");
00951     if (! tok) return false;
00952 
00953     // grab the latitude
00954     char *latp = strtok(NULL, ",");
00955     if (! latp) return false;
00956 
00957     // grab longitude
00958     char *longp = strtok(NULL, ",");
00959     if (! longp) return false;
00960 
00961     *lat = atof(latp);
00962     *lon = atof(longp);
00963 
00964     // only grab altitude if needed
00965     if (altitude != NULL) {
00966       // grab altitude
00967       char *altp = strtok(NULL, ",");
00968       if (! altp) return false;
00969 
00970       *altitude = atof(altp);
00971     }
00972 
00973     // only grab speed if needed
00974     if (speed_kph != NULL) {
00975       // grab the speed in km/h
00976       char *speedp = strtok(NULL, ",");
00977       if (! speedp) return false;
00978 
00979       *speed_kph = atof(speedp);
00980     }
00981 
00982     // only grab heading if needed
00983     if (heading != NULL) {
00984 
00985       // grab the speed in knots
00986       char *coursep = strtok(NULL, ",");
00987       if (! coursep) return false;
00988 
00989       *heading = atof(coursep);
00990     }
00991   }
00992   else {
00993     // Parse 808 V1 response.
00994 
00995     // skip mode
00996     char *tok = strtok(gpsbuffer, ",");
00997     if (! tok) return false;
00998 
00999     // skip date
01000     tok = strtok(NULL, ",");
01001     if (! tok) return false;
01002 
01003     // skip fix
01004     tok = strtok(NULL, ",");
01005     if (! tok) return false;
01006 
01007     // grab the latitude
01008     char *latp = strtok(NULL, ",");
01009     if (! latp) return false;
01010 
01011     // grab latitude direction
01012     char *latdir = strtok(NULL, ",");
01013     if (! latdir) return false;
01014 
01015     // grab longitude
01016     char *longp = strtok(NULL, ",");
01017     if (! longp) return false;
01018 
01019     // grab longitude direction
01020     char *longdir = strtok(NULL, ",");
01021     if (! longdir) return false;
01022 
01023     double latitude = atof(latp);
01024     double longitude = atof(longp);
01025 
01026     // convert latitude from minutes to decimal
01027     float degrees = floor(latitude / 100);
01028     double minutes = latitude - (100 * degrees);
01029     minutes /= 60;
01030     degrees += minutes;
01031 
01032     // turn direction into + or -
01033     if (latdir[0] == 'S') degrees *= -1;
01034 
01035     *lat = degrees;
01036 
01037     // convert longitude from minutes to decimal
01038     degrees = floor(longitude / 100);
01039     minutes = longitude - (100 * degrees);
01040     minutes /= 60;
01041     degrees += minutes;
01042 
01043     // turn direction into + or -
01044     if (longdir[0] == 'W') degrees *= -1;
01045 
01046     *lon = degrees;
01047 
01048     // only grab speed if needed
01049     if (speed_kph != NULL) {
01050 
01051       // grab the speed in knots
01052       char *speedp = strtok(NULL, ",");
01053       if (! speedp) return false;
01054 
01055       // convert to kph
01056       *speed_kph = atof(speedp) * 1.852;
01057 
01058     }
01059 
01060     // only grab heading if needed
01061     if (heading != NULL) {
01062 
01063       // grab the speed in knots
01064       char *coursep = strtok(NULL, ",");
01065       if (! coursep) return false;
01066 
01067       *heading = atof(coursep);
01068 
01069     }
01070 
01071     // no need to continue
01072     if (altitude == NULL)
01073       return true;
01074 
01075     // we need at least a 3D fix for altitude
01076     if (GPSstatus() < 3)
01077       return false;
01078 
01079     // grab the mode 0 gps csv from the sim808
01080     res_len = getGPS(0, gpsbuffer, 120);
01081 
01082     // make sure we have a response
01083     if (res_len == 0)
01084       return false;
01085 
01086     // skip mode
01087     tok = strtok(gpsbuffer, ",");
01088     if (! tok) return false;
01089 
01090     // skip lat
01091     tok = strtok(NULL, ",");
01092     if (! tok) return false;
01093 
01094     // skip long
01095     tok = strtok(NULL, ",");
01096     if (! tok) return false;
01097 
01098     // grab altitude
01099     char *altp = strtok(NULL, ",");
01100     if (! altp) return false;
01101 
01102     *altitude = atof(altp);
01103   }
01104 
01105   return true;
01106 
01107 }
01108 
01109 boolean Adafruit_FONA::enableGPSNMEA(uint8_t i) {
01110 
01111   char sendbuff[15] = "AT+CGPSOUT=000";
01112   sendbuff[11] = (i / 100) + '0';
01113   i %= 100;
01114   sendbuff[12] = (i / 10) + '0';
01115   i %= 10;
01116   sendbuff[13] = i + '0';
01117 
01118   if (_type == FONA808_V2) {
01119     if (i)
01120       return sendCheckReply(F("AT+CGNSTST=1"), ok_reply);
01121     else
01122       return sendCheckReply(F("AT+CGNSTST=0"), ok_reply);
01123   } else {
01124     return sendCheckReply(sendbuff, ok_reply, 2000);
01125   }
01126 }
01127 
01128 
01129 /********* GPRS **********************************************************/
01130 
01131 
01132 boolean Adafruit_FONA::enableGPRS(boolean onoff) {
01133 
01134   if (onoff) {
01135     // disconnect all sockets
01136     sendCheckReply(F("AT+CIPSHUT"), F("SHUT OK"), 20000);
01137 
01138     if (! sendCheckReply(F("AT+CGATT=1"), ok_reply, 10000))
01139       return false;
01140 
01141     // set bearer profile! connection type GPRS
01142     if (! sendCheckReply(F("AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\""),
01143                ok_reply, 10000))
01144       return false;
01145 
01146     // set bearer profile access point name
01147     if (apn) {
01148       // Send command AT+SAPBR=3,1,"APN","<apn value>" where <apn value> is the configured APN value.
01149       if (! sendCheckReplyQuoted(F("AT+SAPBR=3,1,\"APN\","), apn, ok_reply, 10000))
01150         return false;
01151 
01152       // send AT+CSTT,"apn","user","pass"
01153       flushInput();
01154 
01155       mySerial->print(F("AT+CSTT=\""));
01156       mySerial->print(apn);
01157       if (apnusername) {
01158     mySerial->print("\",\"");
01159     mySerial->print(apnusername);
01160       }
01161       if (apnpassword) {
01162     mySerial->print("\",\"");
01163     mySerial->print(apnpassword);
01164       }
01165       mySerial->println("\"");
01166 
01167       DEBUG_PRINT(F("\t---> ")); DEBUG_PRINT(F("AT+CSTT=\""));
01168       DEBUG_PRINT(apn); 
01169       
01170       if (apnusername) {
01171     DEBUG_PRINT("\",\"");
01172     DEBUG_PRINT(apnusername); 
01173       }
01174       if (apnpassword) {
01175     DEBUG_PRINT("\",\"");
01176     DEBUG_PRINT(apnpassword); 
01177       }
01178       DEBUG_PRINTLN("\"");
01179       
01180       if (! expectReply(ok_reply)) return false;
01181     
01182       // set username/password
01183       if (apnusername) {
01184         // Send command AT+SAPBR=3,1,"USER","<user>" where <user> is the configured APN username.
01185         if (! sendCheckReplyQuoted(F("AT+SAPBR=3,1,\"USER\","), apnusername, ok_reply, 10000))
01186           return false;
01187       }
01188       if (apnpassword) {
01189         // Send command AT+SAPBR=3,1,"PWD","<password>" where <password> is the configured APN password.
01190         if (! sendCheckReplyQuoted(F("AT+SAPBR=3,1,\"PWD\","), apnpassword, ok_reply, 10000))
01191           return false;
01192       }
01193     }
01194 
01195     // open GPRS context
01196     if (! sendCheckReply(F("AT+SAPBR=1,1"), ok_reply, 30000))
01197       return false;
01198 
01199     // bring up wireless connection
01200     if (! sendCheckReply(F("AT+CIICR"), ok_reply, 10000))
01201       return false;
01202 
01203   } else {
01204     // disconnect all sockets
01205     if (! sendCheckReply(F("AT+CIPSHUT"), F("SHUT OK"), 20000))
01206       return false;
01207 
01208     // close GPRS context
01209     if (! sendCheckReply(F("AT+SAPBR=0,1"), ok_reply, 10000))
01210       return false;
01211 
01212     if (! sendCheckReply(F("AT+CGATT=0"), ok_reply, 10000))
01213       return false;
01214 
01215   }
01216   return true;
01217 }
01218 
01219 boolean Adafruit_FONA_3G::enableGPRS(boolean onoff) {
01220 
01221   if (onoff) {
01222     // disconnect all sockets
01223     //sendCheckReply(F("AT+CIPSHUT"), F("SHUT OK"), 5000);
01224 
01225     if (! sendCheckReply(F("AT+CGATT=1"), ok_reply, 10000))
01226       return false;
01227 
01228 
01229     // set bearer profile access point name
01230     if (apn) {
01231       // Send command AT+CGSOCKCONT=1,"IP","<apn value>" where <apn value> is the configured APN name.
01232       if (! sendCheckReplyQuoted(F("AT+CGSOCKCONT=1,\"IP\","), apn, ok_reply, 10000))
01233         return false;
01234 
01235       // set username/password
01236       if (apnusername) {
01237     char authstring[100] = "AT+CGAUTH=1,1,\"";
01238     char *strp = authstring + strlen(authstring);
01239     prog_char_strcpy(strp, (prog_char *)apnusername);
01240     strp+=prog_char_strlen((prog_char *)apnusername);
01241     strp[0] = '\"';
01242     strp++;
01243     strp[0] = 0;
01244 
01245     if (apnpassword) {
01246       strp[0] = ','; strp++;
01247       strp[0] = '\"'; strp++;
01248       prog_char_strcpy(strp, (prog_char *)apnpassword);
01249       strp+=prog_char_strlen((prog_char *)apnpassword);
01250       strp[0] = '\"';
01251       strp++;
01252       strp[0] = 0;
01253     }
01254 
01255     if (! sendCheckReply(authstring, ok_reply, 10000))
01256       return false;
01257       }
01258     }
01259 
01260     // connect in transparent
01261     if (! sendCheckReply(F("AT+CIPMODE=1"), ok_reply, 10000))
01262       return false;
01263     // open network (?)
01264     if (! sendCheckReply(F("AT+NETOPEN=,,1"), F("Network opened"), 10000))
01265       return false;
01266 
01267     readline(); // eat 'OK'
01268   } else {
01269     // close GPRS context
01270     if (! sendCheckReply(F("AT+NETCLOSE"), F("Network closed"), 10000))
01271       return false;
01272 
01273     readline(); // eat 'OK'
01274   }
01275 
01276   return true;
01277 }
01278 
01279 uint8_t Adafruit_FONA::GPRSstate(void) {
01280   uint16_t state;
01281 
01282   if (! sendParseReply(F("AT+CGATT?"), F("+CGATT: "), &state) )
01283     return -1;
01284 
01285   return state;
01286 }
01287 
01288 void Adafruit_FONA::setGPRSNetworkSettings(FONAFlashStringPtr apn,
01289               FONAFlashStringPtr username, FONAFlashStringPtr password) {
01290   this->apn = apn;
01291   this->apnusername = username;
01292   this->apnpassword = password;
01293 }
01294 
01295 boolean Adafruit_FONA::getGSMLoc(uint16_t *errorcode, char *buff, uint16_t maxlen) {
01296 
01297   getReply(F("AT+CIPGSMLOC=1,1"), (uint16_t)10000);
01298 
01299   if (! parseReply(F("+CIPGSMLOC: "), errorcode))
01300     return false;
01301 
01302   char *p = replybuffer+14;
01303   uint16_t lentocopy = min(maxlen-1, strlen(p));
01304   strncpy(buff, p, lentocopy+1);
01305 
01306   readline(); // eat OK
01307 
01308   return true;
01309 }
01310 
01311 boolean Adafruit_FONA::getGSMLoc(float *lat, float *lon) {
01312 
01313   uint16_t returncode;
01314   char gpsbuffer[120];
01315 
01316   // make sure we could get a response
01317   if (! getGSMLoc(&returncode, gpsbuffer, 120))
01318     return false;
01319 
01320   // make sure we have a valid return code
01321   if (returncode != 0)
01322     return false;
01323 
01324   // +CIPGSMLOC: 0,-74.007729,40.730160,2015/10/15,19:24:55
01325   // tokenize the gps buffer to locate the lat & long
01326   char *longp = strtok(gpsbuffer, ",");
01327   if (! longp) return false;
01328 
01329   char *latp = strtok(NULL, ",");
01330   if (! latp) return false;
01331 
01332   *lat = atof(latp);
01333   *lon = atof(longp);
01334 
01335   return true;
01336 
01337 }
01338 /********* TCP FUNCTIONS  ************************************/
01339 
01340 
01341 boolean Adafruit_FONA::TCPconnect(char *server, uint16_t port) {
01342   flushInput();
01343 
01344   // close all old connections
01345   if (! sendCheckReply(F("AT+CIPSHUT"), F("SHUT OK"), 20000) ) return false;
01346 
01347   // single connection at a time
01348   if (! sendCheckReply(F("AT+CIPMUX=0"), ok_reply) ) return false;
01349 
01350   // manually read data
01351   if (! sendCheckReply(F("AT+CIPRXGET=1"), ok_reply) ) return false;
01352 
01353 
01354   DEBUG_PRINT(F("AT+CIPSTART=\"TCP\",\""));
01355   DEBUG_PRINT(server);
01356   DEBUG_PRINT(F("\",\""));
01357   DEBUG_PRINT(port);
01358   DEBUG_PRINTLN(F("\""));
01359 
01360 
01361   mySerial->print(F("AT+CIPSTART=\"TCP\",\""));
01362   mySerial->print(server);
01363   mySerial->print(F("\",\""));
01364   mySerial->print(port);
01365   mySerial->println(F("\""));
01366 
01367   if (! expectReply(ok_reply)) return false;
01368   if (! expectReply(F("CONNECT OK"))) return false;
01369 
01370   // looks like it was a success (?)
01371   return true;
01372 }
01373 
01374 boolean Adafruit_FONA::TCPclose(void) {
01375   return sendCheckReply(F("AT+CIPCLOSE"), ok_reply);
01376 }
01377 
01378 boolean Adafruit_FONA::TCPconnected(void) {
01379   if (! sendCheckReply(F("AT+CIPSTATUS"), ok_reply, 100) ) return false;
01380   readline(100);
01381 
01382   DEBUG_PRINT (F("\t<--- ")); DEBUG_PRINTLN(replybuffer);
01383 
01384   return (strcmp(replybuffer, "STATE: CONNECT OK") == 0);
01385 }
01386 
01387 boolean Adafruit_FONA::TCPsend(char *packet, uint8_t len) {
01388 
01389   DEBUG_PRINT(F("AT+CIPSEND="));
01390   DEBUG_PRINTLN(len);
01391 #ifdef ADAFRUIT_FONA_DEBUG
01392   for (uint16_t i=0; i<len; i++) {
01393   DEBUG_PRINT(F(" 0x"));
01394   DEBUG_PRINT(packet[i], HEX);
01395   }
01396 #endif
01397   DEBUG_PRINTLN();
01398 
01399 
01400   mySerial->print(F("AT+CIPSEND="));
01401   mySerial->println(len);
01402   readline();
01403 
01404   DEBUG_PRINT (F("\t<--- ")); DEBUG_PRINTLN(replybuffer);
01405 
01406   if (replybuffer[0] != '>') return false;
01407 
01408   mySerial->write(packet, len);
01409   readline(3000); // wait up to 3 seconds to send the data
01410 
01411   DEBUG_PRINT (F("\t<--- ")); DEBUG_PRINTLN(replybuffer);
01412 
01413 
01414   return (strcmp(replybuffer, "SEND OK") == 0);
01415 }
01416 
01417 uint16_t Adafruit_FONA::TCPavailable(void) {
01418   uint16_t avail;
01419 
01420   if (! sendParseReply(F("AT+CIPRXGET=4"), F("+CIPRXGET: 4,"), &avail, ',', 0) ) return false;
01421 
01422 
01423   DEBUG_PRINT (avail); DEBUG_PRINTLN(F(" bytes available"));
01424 
01425 
01426   return avail;
01427 }
01428 
01429 
01430 uint16_t Adafruit_FONA::TCPread(uint8_t *buff, uint8_t len) {
01431   uint16_t avail;
01432 
01433   mySerial->print(F("AT+CIPRXGET=2,"));
01434   mySerial->println(len);
01435   readline();
01436   if (! parseReply(F("+CIPRXGET: 2,"), &avail, ',', 0)) return false;
01437 
01438   readRaw(avail);
01439 
01440 #ifdef ADAFRUIT_FONA_DEBUG
01441   DEBUG_PRINT (avail); DEBUG_PRINTLN(F(" bytes read"));
01442   for (uint8_t i=0;i<avail;i++) {
01443   DEBUG_PRINT(F(" 0x")); DEBUG_PRINT(replybuffer[i], HEX);
01444   }
01445   DEBUG_PRINTLN();
01446 #endif
01447 
01448   memcpy(buff, replybuffer, avail);
01449 
01450   return avail;
01451 }
01452 
01453 
01454 
01455 /********* HTTP LOW LEVEL FUNCTIONS  ************************************/
01456 
01457 boolean Adafruit_FONA::HTTP_init() {
01458   return sendCheckReply(F("AT+HTTPINIT"), ok_reply);
01459 }
01460 
01461 boolean Adafruit_FONA::HTTP_term() {
01462   return sendCheckReply(F("AT+HTTPTERM"), ok_reply);
01463 }
01464 
01465 void Adafruit_FONA::HTTP_para_start(FONAFlashStringPtr parameter,
01466                                     boolean quoted) {
01467   flushInput();
01468 
01469 
01470   DEBUG_PRINT(F("\t---> "));
01471   DEBUG_PRINT(F("AT+HTTPPARA=\""));
01472   DEBUG_PRINT(parameter);
01473   DEBUG_PRINTLN('"');
01474 
01475 
01476   mySerial->print(F("AT+HTTPPARA=\""));
01477   mySerial->print(parameter);
01478   if (quoted)
01479     mySerial->print(F("\",\""));
01480   else
01481     mySerial->print(F("\","));
01482 }
01483 
01484 boolean Adafruit_FONA::HTTP_para_end(boolean quoted) {
01485   if (quoted)
01486     mySerial->println('"');
01487   else
01488     mySerial->println();
01489 
01490   return expectReply(ok_reply);
01491 }
01492 
01493 boolean Adafruit_FONA::HTTP_para(FONAFlashStringPtr parameter,
01494                                  const char *value) {
01495   HTTP_para_start(parameter, true);
01496   mySerial->print(value);
01497   return HTTP_para_end(true);
01498 }
01499 
01500 boolean Adafruit_FONA::HTTP_para(FONAFlashStringPtr parameter,
01501                                  FONAFlashStringPtr value) {
01502   HTTP_para_start(parameter, true);
01503   mySerial->print(value);
01504   return HTTP_para_end(true);
01505 }
01506 
01507 boolean Adafruit_FONA::HTTP_para(FONAFlashStringPtr parameter,
01508                                  int32_t value) {
01509   HTTP_para_start(parameter, false);
01510   mySerial->print(value);
01511   return HTTP_para_end(false);
01512 }
01513 
01514 boolean Adafruit_FONA::HTTP_data(uint32_t size, uint32_t maxTime) {
01515   flushInput();
01516 
01517 
01518   DEBUG_PRINT(F("\t---> "));
01519   DEBUG_PRINT(F("AT+HTTPDATA="));
01520   DEBUG_PRINT(size);
01521   DEBUG_PRINT(',');
01522   DEBUG_PRINTLN(maxTime);
01523 
01524 
01525   mySerial->print(F("AT+HTTPDATA="));
01526   mySerial->print(size);
01527   mySerial->print(",");
01528   mySerial->println(maxTime);
01529 
01530   return expectReply(F("DOWNLOAD"));
01531 }
01532 
01533 boolean Adafruit_FONA::HTTP_action(uint8_t method, uint16_t *status,
01534                                    uint16_t *datalen, int32_t timeout) {
01535   // Send request.
01536   if (! sendCheckReply(F("AT+HTTPACTION="), method, ok_reply))
01537     return false;
01538 
01539   // Parse response status and size.
01540   readline(timeout);
01541   if (! parseReply(F("+HTTPACTION:"), status, ',', 1))
01542     return false;
01543   if (! parseReply(F("+HTTPACTION:"), datalen, ',', 2))
01544     return false;
01545 
01546   return true;
01547 }
01548 
01549 boolean Adafruit_FONA::HTTP_readall(uint16_t *datalen) {
01550   getReply(F("AT+HTTPREAD"));
01551   if (! parseReply(F("+HTTPREAD:"), datalen, ',', 0))
01552     return false;
01553 
01554   return true;
01555 }
01556 
01557 boolean Adafruit_FONA::HTTP_ssl(boolean onoff) {
01558   return sendCheckReply(F("AT+HTTPSSL="), onoff ? 1 : 0, ok_reply);
01559 }
01560 
01561 /********* HTTP HIGH LEVEL FUNCTIONS ***************************/
01562 
01563 boolean Adafruit_FONA::HTTP_GET_start(char *url,
01564               uint16_t *status, uint16_t *datalen){
01565   if (! HTTP_setup(url))
01566     return false;
01567 
01568   // HTTP GET
01569   if (! HTTP_action(FONA_HTTP_GET, status, datalen, 30000))
01570     return false;
01571 
01572   DEBUG_PRINT(F("Status: ")); DEBUG_PRINTLN(*status);
01573   DEBUG_PRINT(F("Len: ")); DEBUG_PRINTLN(*datalen);
01574 
01575   // HTTP response data
01576   if (! HTTP_readall(datalen))
01577     return false;
01578 
01579   return true;
01580 }
01581 
01582 /*
01583 boolean Adafruit_FONA_3G::HTTP_GET_start(char *ipaddr, char *path, uint16_t port
01584                       uint16_t *status, uint16_t *datalen){
01585   char send[100] = "AT+CHTTPACT=\"";
01586   char *sendp = send + strlen(send);
01587   memset(sendp, 0, 100 - strlen(send));
01588 
01589   strcpy(sendp, ipaddr);
01590   sendp+=strlen(ipaddr);
01591   sendp[0] = '\"';
01592   sendp++;
01593   sendp[0] = ',';
01594   itoa(sendp, port);
01595   getReply(send, 500);
01596 
01597   return;
01598 
01599   if (! HTTP_setup(url))
01600 
01601     return false;
01602 
01603   // HTTP GET
01604   if (! HTTP_action(FONA_HTTP_GET, status, datalen))
01605     return false;
01606 
01607   DEBUG_PRINT("Status: "); DEBUG_PRINTLN(*status);
01608   DEBUG_PRINT("Len: "); DEBUG_PRINTLN(*datalen);
01609 
01610   // HTTP response data
01611   if (! HTTP_readall(datalen))
01612     return false;
01613 
01614   return true;
01615 }
01616 */
01617 
01618 void Adafruit_FONA::HTTP_GET_end(void) {
01619   HTTP_term();
01620 }
01621 
01622 boolean Adafruit_FONA::HTTP_POST_start(char *url,
01623               FONAFlashStringPtr contenttype,
01624               const uint8_t *postdata, uint16_t postdatalen,
01625               uint16_t *status, uint16_t *datalen){
01626   if (! HTTP_setup(url))
01627     return false;
01628 
01629   if (! HTTP_para(F("CONTENT"), contenttype)) {
01630     return false;
01631   }
01632 
01633   // HTTP POST data
01634   if (! HTTP_data(postdatalen, 10000))
01635     return false;
01636   mySerial->write(postdata, postdatalen);
01637   if (! expectReply(ok_reply))
01638     return false;
01639 
01640   // HTTP POST
01641   if (! HTTP_action(FONA_HTTP_POST, status, datalen))
01642     return false;
01643 
01644   DEBUG_PRINT(F("Status: ")); DEBUG_PRINTLN(*status);
01645   DEBUG_PRINT(F("Len: ")); DEBUG_PRINTLN(*datalen);
01646 
01647   // HTTP response data
01648   if (! HTTP_readall(datalen))
01649     return false;
01650 
01651   return true;
01652 }
01653 
01654 void Adafruit_FONA::HTTP_POST_end(void) {
01655   HTTP_term();
01656 }
01657 
01658 void Adafruit_FONA::setUserAgent(FONAFlashStringPtr useragent) {
01659   this->useragent = useragent;
01660 }
01661 
01662 void Adafruit_FONA::setHTTPSRedirect(boolean onoff) {
01663   httpsredirect = onoff;
01664 }
01665 
01666 /********* HTTP HELPERS ****************************************/
01667 
01668 boolean Adafruit_FONA::HTTP_setup(char *url) {
01669   // Handle any pending
01670   HTTP_term();
01671 
01672   // Initialize and set parameters
01673   if (! HTTP_init())
01674     return false;
01675   if (! HTTP_para(F("CID"), 1))
01676     return false;
01677   if (! HTTP_para(F("UA"), useragent))
01678     return false;
01679   if (! HTTP_para(F("URL"), url))
01680     return false;
01681 
01682   // HTTPS redirect
01683   if (httpsredirect) {
01684     if (! HTTP_para(F("REDIR"),1))
01685       return false;
01686 
01687     if (! HTTP_ssl(true))
01688       return false;
01689   }
01690 
01691   return true;
01692 }
01693 
01694 /********* HELPERS *********************************************/
01695 
01696 boolean Adafruit_FONA::expectReply(FONAFlashStringPtr reply,
01697                                    uint16_t timeout) {
01698   readline(timeout);
01699 
01700   DEBUG_PRINT(F("\t<--- ")); DEBUG_PRINTLN(replybuffer);
01701 
01702   return (prog_char_strcmp(replybuffer, (prog_char*)reply) == 0);
01703 }
01704 
01705 /********* LOW LEVEL *******************************************/
01706 
01707 inline int Adafruit_FONA::available(void) {
01708   return mySerial->available();
01709 }
01710 
01711 inline size_t Adafruit_FONA::write(uint8_t x) {
01712   return mySerial->write(x);
01713 }
01714 
01715 inline int Adafruit_FONA::read(void) {
01716   return mySerial->read();
01717 }
01718 
01719 inline int Adafruit_FONA::peek(void) {
01720   return mySerial->peek();
01721 }
01722 
01723 inline void Adafruit_FONA::flush() {
01724   mySerial->flush();
01725 }
01726 
01727 void Adafruit_FONA::flushInput() {
01728     // Read all available serial input to flush pending data.
01729     uint16_t timeoutloop = 0;
01730     while (timeoutloop++ < 40) {
01731         while(available()) {
01732             read();
01733             timeoutloop = 0;  // If char was received reset the timer
01734         }
01735         delay(1);
01736     }
01737 }
01738 
01739 uint16_t Adafruit_FONA::readRaw(uint16_t b) {
01740   uint16_t idx = 0;
01741 
01742   while (b && (idx < sizeof(replybuffer)-1)) {
01743     if (mySerial->available()) {
01744       replybuffer[idx] = mySerial->read();
01745       idx++;
01746       b--;
01747     }
01748   }
01749   replybuffer[idx] = 0;
01750 
01751   return idx;
01752 }
01753 
01754 uint8_t Adafruit_FONA::readline(uint16_t timeout, boolean multiline) {
01755   uint16_t replyidx = 0;
01756 
01757   while (timeout--) {
01758     if (replyidx >= 254) {
01759       //DEBUG_PRINTLN(F("SPACE"));
01760       break;
01761     }
01762 
01763     while(mySerial->available()) {
01764       char c =  mySerial->read();
01765       if (c == '\r') continue;
01766       if (c == 0xA) {
01767         if (replyidx == 0)   // the first 0x0A is ignored
01768           continue;
01769 
01770         if (!multiline) {
01771           timeout = 0;         // the second 0x0A is the end of the line
01772           break;
01773         }
01774       }
01775       replybuffer[replyidx] = c;
01776       //DEBUG_PRINT(c, HEX); DEBUG_PRINT("#"); DEBUG_PRINTLN(c);
01777       replyidx++;
01778     }
01779 
01780     if (timeout == 0) {
01781       //DEBUG_PRINTLN(F("TIMEOUT"));
01782       break;
01783     }
01784     delay(1);
01785   }
01786   replybuffer[replyidx] = 0;  // null term
01787   return replyidx;
01788 }
01789 
01790 uint8_t Adafruit_FONA::getReply(char *send, uint16_t timeout) {
01791   flushInput();
01792 
01793 
01794   DEBUG_PRINT(F("\t---> ")); DEBUG_PRINTLN(send);
01795 
01796 
01797   mySerial->println(send);
01798 
01799   uint8_t l = readline(timeout);
01800 
01801   DEBUG_PRINT (F("\t<--- ")); DEBUG_PRINTLN(replybuffer);
01802 
01803   return l;
01804 }
01805 
01806 uint8_t Adafruit_FONA::getReply(FONAFlashStringPtr send, uint16_t timeout) {
01807   flushInput();
01808 
01809 
01810   DEBUG_PRINT(F("\t---> ")); DEBUG_PRINTLN(send);
01811 
01812 
01813   mySerial->println(send);
01814 
01815   uint8_t l = readline(timeout);
01816 
01817   DEBUG_PRINT (F("\t<--- ")); DEBUG_PRINTLN(replybuffer);
01818 
01819   return l;
01820 }
01821 
01822 // Send prefix, suffix, and newline. Return response (and also set replybuffer with response).
01823 uint8_t Adafruit_FONA::getReply(FONAFlashStringPtr prefix, char *suffix, uint16_t timeout) {
01824   flushInput();
01825 
01826 
01827   DEBUG_PRINT(F("\t---> ")); DEBUG_PRINT(prefix); DEBUG_PRINTLN(suffix);
01828 
01829 
01830   mySerial->print(prefix);
01831   mySerial->println(suffix);
01832 
01833   uint8_t l = readline(timeout);
01834 
01835   DEBUG_PRINT (F("\t<--- ")); DEBUG_PRINTLN(replybuffer);
01836 
01837   return l;
01838 }
01839 
01840 // Send prefix, suffix, and newline. Return response (and also set replybuffer with response).
01841 uint8_t Adafruit_FONA::getReply(FONAFlashStringPtr prefix, int32_t suffix, uint16_t timeout) {
01842   flushInput();
01843 
01844 
01845   DEBUG_PRINT(F("\t---> ")); DEBUG_PRINT(prefix); DEBUG_PRINTLN(suffix, DEC);
01846 
01847 
01848   mySerial->print(prefix);
01849   mySerial->println(suffix, DEC);
01850 
01851   uint8_t l = readline(timeout);
01852 
01853   DEBUG_PRINT (F("\t<--- ")); DEBUG_PRINTLN(replybuffer);
01854 
01855   return l;
01856 }
01857 
01858 // Send prefix, suffix, suffix2, and newline. Return response (and also set replybuffer with response).
01859 uint8_t Adafruit_FONA::getReply(FONAFlashStringPtr prefix, int32_t suffix1, int32_t suffix2, uint16_t timeout) {
01860   flushInput();
01861 
01862 
01863   DEBUG_PRINT(F("\t---> ")); DEBUG_PRINT(prefix);
01864   DEBUG_PRINT(suffix1, DEC); DEBUG_PRINT(','); DEBUG_PRINTLN(suffix2, DEC);
01865 
01866 
01867   mySerial->print(prefix);
01868   mySerial->print(suffix1);
01869   mySerial->print(',');
01870   mySerial->println(suffix2, DEC);
01871 
01872   uint8_t l = readline(timeout);
01873 
01874   DEBUG_PRINT (F("\t<--- ")); DEBUG_PRINTLN(replybuffer);
01875 
01876   return l;
01877 }
01878 
01879 // Send prefix, ", suffix, ", and newline. Return response (and also set replybuffer with response).
01880 uint8_t Adafruit_FONA::getReplyQuoted(FONAFlashStringPtr prefix, FONAFlashStringPtr suffix, uint16_t timeout) {
01881   flushInput();
01882 
01883 
01884   DEBUG_PRINT(F("\t---> ")); DEBUG_PRINT(prefix);
01885   DEBUG_PRINT('"'); DEBUG_PRINT(suffix); DEBUG_PRINTLN('"');
01886 
01887 
01888   mySerial->print(prefix);
01889   mySerial->print('"');
01890   mySerial->print(suffix);
01891   mySerial->println('"');
01892 
01893   uint8_t l = readline(timeout);
01894 
01895   DEBUG_PRINT (F("\t<--- ")); DEBUG_PRINTLN(replybuffer);
01896 
01897   return l;
01898 }
01899 
01900 boolean Adafruit_FONA::sendCheckReply(char *send, char *reply, uint16_t timeout) {
01901   if (! getReply(send, timeout) )
01902       return false;
01903 /*
01904   for (uint8_t i=0; i<strlen(replybuffer); i++) {
01905   DEBUG_PRINT(replybuffer[i], HEX); DEBUG_PRINT(" ");
01906   }
01907   DEBUG_PRINTLN();
01908   for (uint8_t i=0; i<strlen(reply); i++) {
01909     DEBUG_PRINT(reply[i], HEX); DEBUG_PRINT(" ");
01910   }
01911   DEBUG_PRINTLN();
01912   */
01913   return (strcmp(replybuffer, reply) == 0);
01914 }
01915 
01916 boolean Adafruit_FONA::sendCheckReply(FONAFlashStringPtr send, FONAFlashStringPtr reply, uint16_t timeout) {
01917     if (! getReply(send, timeout) )
01918         return false;
01919 
01920   return (prog_char_strcmp(replybuffer, (prog_char*)reply) == 0);
01921 }
01922 
01923 boolean Adafruit_FONA::sendCheckReply(char* send, FONAFlashStringPtr reply, uint16_t timeout) {
01924   if (! getReply(send, timeout) )
01925       return false;
01926   return (prog_char_strcmp(replybuffer, (prog_char*)reply) == 0);
01927 }
01928 
01929 
01930 // Send prefix, suffix, and newline.  Verify FONA response matches reply parameter.
01931 boolean Adafruit_FONA::sendCheckReply(FONAFlashStringPtr prefix, char *suffix, FONAFlashStringPtr reply, uint16_t timeout) {
01932   getReply(prefix, suffix, timeout);
01933   return (prog_char_strcmp(replybuffer, (prog_char*)reply) == 0);
01934 }
01935 
01936 // Send prefix, suffix, and newline.  Verify FONA response matches reply parameter.
01937 boolean Adafruit_FONA::sendCheckReply(FONAFlashStringPtr prefix, int32_t suffix, FONAFlashStringPtr reply, uint16_t timeout) {
01938   getReply(prefix, suffix, timeout);
01939   return (prog_char_strcmp(replybuffer, (prog_char*)reply) == 0);
01940 }
01941 
01942 // Send prefix, suffix, suffix2, and newline.  Verify FONA response matches reply parameter.
01943 boolean Adafruit_FONA::sendCheckReply(FONAFlashStringPtr prefix, int32_t suffix1, int32_t suffix2, FONAFlashStringPtr reply, uint16_t timeout) {
01944   getReply(prefix, suffix1, suffix2, timeout);
01945   return (prog_char_strcmp(replybuffer, (prog_char*)reply) == 0);
01946 }
01947 
01948 // Send prefix, ", suffix, ", and newline.  Verify FONA response matches reply parameter.
01949 boolean Adafruit_FONA::sendCheckReplyQuoted(FONAFlashStringPtr prefix, FONAFlashStringPtr suffix, FONAFlashStringPtr reply, uint16_t timeout) {
01950   getReplyQuoted(prefix, suffix, timeout);
01951   return (prog_char_strcmp(replybuffer, (prog_char*)reply) == 0);
01952 }
01953 
01954 
01955 boolean Adafruit_FONA::parseReply(FONAFlashStringPtr toreply,
01956           uint16_t *v, char divider, uint8_t index) {
01957   char *p = prog_char_strstr(replybuffer, (prog_char*)toreply);  // get the pointer to the voltage
01958   if (p == 0) return false;
01959   p+=prog_char_strlen((prog_char*)toreply);
01960   //DEBUG_PRINTLN(p);
01961   for (uint8_t i=0; i<index;i++) {
01962     // increment dividers
01963     p = strchr(p, divider);
01964     if (!p) return false;
01965     p++;
01966     //DEBUG_PRINTLN(p);
01967 
01968   }
01969   *v = atoi(p);
01970 
01971   return true;
01972 }
01973 
01974 boolean Adafruit_FONA::parseReply(FONAFlashStringPtr toreply,
01975           char *v, char divider, uint8_t index) {
01976   uint8_t i=0;
01977   char *p = prog_char_strstr(replybuffer, (prog_char*)toreply);
01978   if (p == 0) return false;
01979   p+=prog_char_strlen((prog_char*)toreply);
01980 
01981   for (i=0; i<index;i++) {
01982     // increment dividers
01983     p = strchr(p, divider);
01984     if (!p) return false;
01985     p++;
01986   }
01987 
01988   for(i=0; i<strlen(p);i++) {
01989     if(p[i] == divider)
01990       break;
01991     v[i] = p[i];
01992   }
01993 
01994   v[i] = '\0';
01995 
01996   return true;
01997 }
01998 
01999 // Parse a quoted string in the response fields and copy its value (without quotes)
02000 // to the specified character array (v).  Only up to maxlen characters are copied
02001 // into the result buffer, so make sure to pass a large enough buffer to handle the
02002 // response.
02003 boolean Adafruit_FONA::parseReplyQuoted(FONAFlashStringPtr toreply,
02004           char *v, int maxlen, char divider, uint8_t index) {
02005   uint8_t i=0, j;
02006   // Verify response starts with toreply.
02007   char *p = prog_char_strstr(replybuffer, (prog_char*)toreply);
02008   if (p == 0) return false;
02009   p+=prog_char_strlen((prog_char*)toreply);
02010 
02011   // Find location of desired response field.
02012   for (i=0; i<index;i++) {
02013     // increment dividers
02014     p = strchr(p, divider);
02015     if (!p) return false;
02016     p++;
02017   }
02018 
02019   // Copy characters from response field into result string.
02020   for(i=0, j=0; j<maxlen && i<strlen(p); ++i) {
02021     // Stop if a divier is found.
02022     if(p[i] == divider)
02023       break;
02024     // Skip any quotation marks.
02025     else if(p[i] == '"')
02026       continue;
02027     v[j++] = p[i];
02028   }
02029 
02030   // Add a null terminator if result string buffer was not filled.
02031   if (j < maxlen)
02032     v[j] = '\0';
02033 
02034   return true;
02035 }
02036 
02037 boolean Adafruit_FONA::sendParseReply(FONAFlashStringPtr tosend,
02038                       FONAFlashStringPtr toreply,
02039                       uint16_t *v, char divider, uint8_t index) {
02040   getReply(tosend);
02041 
02042   if (! parseReply(toreply, v, divider, index)) return false;
02043 
02044   readline(); // eat 'OK'
02045 
02046   return true;
02047 }
02048 
02049 
02050 // needed for CBC and others
02051 
02052 boolean Adafruit_FONA_3G::sendParseReply(FONAFlashStringPtr tosend,
02053                       FONAFlashStringPtr toreply,
02054                       float *f, char divider, uint8_t index) {
02055   getReply(tosend);
02056 
02057   if (! parseReply(toreply, f, divider, index)) return false;
02058 
02059   readline(); // eat 'OK'
02060 
02061   return true;
02062 }
02063 
02064 
02065 boolean Adafruit_FONA_3G::parseReply(FONAFlashStringPtr toreply,
02066           float *f, char divider, uint8_t index) {
02067   char *p = prog_char_strstr(replybuffer, (prog_char*)toreply);  // get the pointer to the voltage
02068   if (p == 0) return false;
02069   p+=prog_char_strlen((prog_char*)toreply);
02070   //DEBUG_PRINTLN(p);
02071   for (uint8_t i=0; i<index;i++) {
02072     // increment dividers
02073     p = strchr(p, divider);
02074     if (!p) return false;
02075     p++;
02076     //DEBUG_PRINTLN(p);
02077 
02078   }
02079   *f = atof(p);
02080 
02081   return true;
02082 }