Library for the Adafruit FONA. This is a port of the original Arduino library available at: https://github.com/adafruit/Adafruit_FONA_Library . - Modified by Marc PLOUHINEC 27/06/2015 for use in mbed - Modified by lionel VOIRIN 05/08/2018 for use Adafruit FONA 3
Dependents: Adafruit_FONA_3G_Library_Test
Adafruit_FONA.cpp
- Committer:
- Nels885
- Date:
- 2019-03-02
- Revision:
- 11:5f66d83249ea
- Parent:
- 10:7951d9691cb2
- Child:
- 12:7a6b5413b407
File content as of revision 11:5f66d83249ea:
/*************************************************** This is a library for our Adafruit FONA Cellular Module Designed specifically to work with the Adafruit FONA ----> http://www.adafruit.com/products/1946 ----> http://www.adafruit.com/products/1963 These displays use TTL Serial to communicate, 2 pins are required to interface Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit! Written by Limor Fried/Ladyada for Adafruit Industries. BSD license, all text above must be included in any redistribution ****************************************************/ /* * Modified by Marc PLOUHINEC 27/06/2015 for use in mbed * Modified by lionel VOIRIN 05/08/2018 for use Adafruit FONA 3G */ #include <algorithm> #include "Adafruit_FONA.h" #define HIGH 1 #define LOW 0 Adafruit_FONA::Adafruit_FONA(PinName tx, PinName rx, PinName rst, PinName key) : _keypin(key, false), _rstpin(rst, false), mySerial(tx, rx) { apn = "FONAnet"; apnusername = 0; apnpassword = 0; httpsredirect = false; useragent = "FONA"; ok_reply = "OK"; _incomingCall = false; eventListener = 0; rxBufferInIndex = 0; rxBufferOutIndex = 0; currentReceivedLineSize = 0; } uint8_t Adafruit_FONA::type(void) { return _type; } bool Adafruit_FONA::begin(int baudrate) { mySerial.baud(baudrate); mySerial.attach(this, &Adafruit_FONA::onSerialDataReceived, Serial::RxIrq); powerOn(); // turn off Echo! sendCheckReply("ATE0", ok_reply); wait_ms(100); if (! sendCheckReply("ATE0", ok_reply)) { return false; } // turn on hangupitude sendCheckReply("AT+CVHU=0", ok_reply); wait_ms(100); flushInput(); #ifdef ADAFRUIT_FONA_DEBUG printf("\t---> %s\r\n", "ATI"); #endif mySerial.printf("%s\r\n", "ATI"); readline(500, true); #ifdef ADAFRUIT_FONA_DEBUG printf("\t<--- %s\r\n", replybuffer); #endif if (strstr(replybuffer, "SIM808 R14") != 0) { _type = FONA808_V2; } else if (strstr(replybuffer, "SIM808 R13") != 0) { _type = FONA808_V1; } else if (strstr(replybuffer, "SIM800 R13") != 0) { _type = FONA800L; } else if (strstr(replybuffer, "SIMCOM_SIM5320A") != 0) { _type = FONA3G_A; } else if (strstr(replybuffer, "SIMCOM_SIM5320E") != 0) { _type = FONA3G_E; } if (_type == FONA800L) { // determine if L or H printf("\t---> %s\r\n", "AT+GMM"); mySerial.printf("%s\r\n", "AT+GMM"); readline(500, true); printf("\t<--- %s\r\n", replybuffer); if (strstr(replybuffer, "SIM800H") != 0) _type = FONA800H; } #if defined(FONA_PREF_SMS_STORAGE) sendCheckReply("AT+CPMS=" FONA_PREF_SMS_STORAGE "," FONA_PREF_SMS_STORAGE "," FONA_PREF_SMS_STORAGE, ok_reply); #endif return true; } void Adafruit_FONA::powerOn() { _keypin = LOW; _rstpin = HIGH; wait_ms(10); _rstpin = LOW; wait_ms(100); _rstpin = HIGH; #ifdef ADAFRUIT_FONA_DEBUG printf("Attempting to open comm with ATs\r\n"); #endif // give 3 seconds to reboot int16_t timeout = 7000; while (timeout > 0) { while (readable()) getc(); if (sendCheckReply("AT", ok_reply)) break; while (readable()) getc(); if (sendCheckReply("AT", "AT")) break; wait_ms(500); timeout -= 500; } if (timeout <= 0) { #ifdef ADAFRUIT_FONA_DEBUG printf("Timeout: No response to AT... last ditch attempt.\r\n"); #endif sendCheckReply("AT", ok_reply); wait_ms(100); sendCheckReply("AT", ok_reply); wait_ms(100); sendCheckReply("AT", ok_reply); wait_ms(100); } _keypin = HIGH; } void Adafruit_FONA::powerOff() { _keypin = LOW; wait(5); _keypin = HIGH; } void Adafruit_FONA::setEventListener(EventListener *eventListener) { this->eventListener = eventListener; } /********* Stream ********************************************/ int Adafruit_FONA::_putc(int value) { return mySerial.putc(value); } int Adafruit_FONA::_getc() { __disable_irq(); // Start Critical Section - don't interrupt while changing global buffer variables // Wait for data if the buffer is empty if (isRxBufferEmpty()) { __enable_irq(); // End Critical Section - need to allow rx interrupt to get new characters for buffer while(isRxBufferEmpty()); __disable_irq(); // Start Critical Section - don't interrupt while changing global buffer variables } int data = rxBuffer[rxBufferOutIndex]; incrementRxBufferOutIndex(); __enable_irq(); // End Critical Section return data; } int Adafruit_FONA::readable() { return !isRxBufferEmpty(); } void Adafruit_FONA::onSerialDataReceived() { while (mySerial.readable() && !isRxBufferFull()) { int data = mySerial.getc(); rxBuffer[rxBufferInIndex] = data; // // Analyze the received data in order to detect events like RING or NO CARRIER // // Copy the data in the current line if (currentReceivedLineSize < RX_BUFFER_SIZE && data != '\r' && data != '\n') { currentReceivedLine[currentReceivedLineSize] = (char) data; currentReceivedLineSize++; } // Check if the line is complete if (data == '\n') { currentReceivedLine[currentReceivedLineSize] = 0; if (eventListener != NULL) { // Check if we have a special event if (strcmp(currentReceivedLine, "RING") == 0) { eventListener->onRing(); } else if (strcmp(currentReceivedLine, "NO CARRIER") == 0) { eventListener->onNoCarrier(); } } currentReceivedLineSize = 0; } incrementRxBufferInIndex(); } } /********* Serial port ********************************************/ bool Adafruit_FONA::getBaudrate(uint32_t *baud) { return sendParseReply("AT+IPREX?", "+IPREX: ", baud); } bool Adafruit_FONA::setBaudrate(uint32_t baud) { return sendCheckReply("AT+IPREX=", baud, ok_reply); } /********* Real Time Clock ********************************************/ bool Adafruit_FONA::enableRTC(uint8_t i) { if (! sendCheckReply("AT+CLTS=", i, ok_reply)) return false; return sendCheckReply("AT&W", ok_reply); } /********* BATTERY & ADC ********************************************/ /* returns value in mV (uint16_t) */ bool Adafruit_FONA::getBattVoltage(uint16_t *v) { return sendParseReply("AT+CBC", "+CBC: ", v, ',', 2); } /* returns value in mV (uint16_t) */ bool Adafruit_FONA_3G::getBattVoltage(uint16_t *v) { float f; bool b = sendParseReply("AT+CBC", "+CBC: ", &f, ',', 2); *v = f*1000; return b; } /* returns the percentage charge of battery as reported by sim800 */ bool Adafruit_FONA::getBattPercent(uint16_t *p) { return sendParseReply("AT+CBC", "+CBC: ", p, ',', 1); } bool Adafruit_FONA::getADCVoltage(uint16_t *v) { return sendParseReply("AT+CADC?", "+CADC: 1,", v); } /********* SIM ***********************************************************/ uint8_t Adafruit_FONA::unlockSIM(char *pin) { // AT+CPIN=0000 char sendbuff[14] = "AT+CPIN="; sendbuff[8] = pin[0]; sendbuff[9] = pin[1]; sendbuff[10] = pin[2]; sendbuff[11] = pin[3]; sendbuff[12] = NULL; return sendCheckReply(sendbuff, ok_reply); } uint8_t Adafruit_FONA_3G::unlockSIM(char *pin) { // AT+CPIN=0000 char sendbuff[14] = "AT+CPIN="; sendbuff[8] = pin[0]; sendbuff[9] = pin[1]; sendbuff[10] = pin[2]; sendbuff[11] = pin[3]; sendbuff[12] = NULL; if (! sendCheckReply(sendbuff, ok_reply)) return false; if (! expectReply("+CPIN: READY")) return false; if (! expectReply("SMS DONE")) return false; if (! expectReply("PB DONE")) return false; return true; } uint8_t Adafruit_FONA::getSIMCCID(char *ccid) { getReply("AT+CCID"); // up to 28 chars for reply, 20 char total ccid if (replybuffer[0] == '+') { // fona 3g? strncpy(ccid, replybuffer+8, 20); } else { // fona 800 or 800 strncpy(ccid, replybuffer, 20); } ccid[20] = 0; readline(); // eat 'OK' return strlen(ccid); } /********* IMEI **********************************************************/ uint8_t Adafruit_FONA::getIMEI(char *imei) { getReply("AT+GSN"); // up to 15 chars strncpy(imei, replybuffer, 15); imei[15] = 0; readline(); // eat 'OK' return strlen(imei); } /********* NETWORK *******************************************************/ uint8_t Adafruit_FONA::getNetworkStatus(void) { uint16_t status; if (! sendParseReply("AT+CREG?", "+CREG: ", &status, ',', 1)) return 0; return status; } uint8_t Adafruit_FONA::getRSSI(void) { uint16_t reply; if (! sendParseReply("AT+CSQ", "+CSQ: ", &reply) ) return 0; return reply; } /********* AUDIO *******************************************************/ bool Adafruit_FONA::setAudio(uint8_t a) { // 0 is headset, 1 is external audio if (a > 1) return false; return sendCheckReply("AT+CHFA=", a, ok_reply); } uint8_t Adafruit_FONA::getVolume(void) { uint16_t reply; if (! sendParseReply("AT+CLVL?", "+CLVL: ", &reply) ) return 0; return reply; } bool Adafruit_FONA::setVolume(uint8_t i) { return sendCheckReply("AT+CLVL=", i, ok_reply); } bool Adafruit_FONA::playDTMF(char dtmf) { char str[4]; str[0] = '\"'; str[1] = dtmf; str[2] = '\"'; str[3] = 0; return sendCheckReply("AT+CLDTMF=3,", str, ok_reply); } bool Adafruit_FONA::playToolkitTone(uint8_t t, uint16_t len) { return sendCheckReply("AT+STTONE=1,", t, len, ok_reply); } bool Adafruit_FONA::setMicVolume(uint8_t a, uint8_t level) { // 0 is headset, 1 is external audio if (a > 1) return false; return sendCheckReply("AT+CMIC=", a, level, ok_reply); } /********* FM RADIO *******************************************************/ bool Adafruit_FONA::FMradio(bool onoff, uint8_t a) { if (! onoff) { return sendCheckReply("AT+FMCLOSE", ok_reply); } // 0 is headset, 1 is external audio if (a > 1) return false; return sendCheckReply("AT+FMOPEN=", a, ok_reply); } bool Adafruit_FONA::tuneFMradio(uint16_t station) { // Fail if FM station is outside allowed range. if ((station < 870) || (station > 1090)) return false; return sendCheckReply("AT+FMFREQ=", station, ok_reply); } bool Adafruit_FONA::setFMVolume(uint8_t i) { // Fail if volume is outside allowed range (0-6). if (i > 6) { return false; } // Send FM volume command and verify response. return sendCheckReply("AT+FMVOLUME=", i, ok_reply); } int8_t Adafruit_FONA::getFMVolume() { uint16_t level; if (! sendParseReply("AT+FMVOLUME?", "+FMVOLUME: ", &level) ) return 0; return level; } int8_t Adafruit_FONA::getFMSignalLevel(uint16_t station) { // Fail if FM station is outside allowed range. if ((station < 875) || (station > 1080)) { return -1; } // Send FM signal level query command. // Note, need to explicitly send timeout so right overload is chosen. getReply("AT+FMSIGNAL=", station, FONA_DEFAULT_TIMEOUT_MS); // Check response starts with expected value. char *p = strstr(replybuffer, "+FMSIGNAL: "); if (p == 0) return -1; p+=11; // Find second colon to get start of signal quality. p = strchr(p, ':'); if (p == 0) return -1; p+=1; // Parse signal quality. int8_t level = atoi(p); readline(); // eat the "OK" return level; } /********* PWM/BUZZER **************************************************/ bool Adafruit_FONA::setPWM(uint16_t period, uint8_t duty) { if (period > 2000) return false; if (duty > 100) return false; return sendCheckReply("AT+SPWM=0,", period, duty, ok_reply); } /********* CALL PHONES **************************************************/ bool Adafruit_FONA::callPhone(char *number) { char sendbuff[35] = "ATD"; strncpy(sendbuff+3, number, min((int)30, (int)strlen(number))); uint8_t x = strlen(sendbuff); sendbuff[x] = ';'; sendbuff[x+1] = 0; return sendCheckReply(sendbuff, ok_reply); } bool Adafruit_FONA::hangUp(void) { return sendCheckReply("ATH0", ok_reply); } bool Adafruit_FONA_3G::hangUp(void) { getReply("ATH"); return (strstr(replybuffer, "VOICE CALL: END") != 0); } bool Adafruit_FONA::pickUp(void) { return sendCheckReply("ATA", ok_reply); } bool Adafruit_FONA_3G::pickUp(void) { return sendCheckReply("ATA", "VOICE CALL: BEGIN"); } void Adafruit_FONA::onIncomingCall() { #ifdef ADAFRUIT_FONA_DEBUG printf("> Incoming call...\r\n"); #endif _incomingCall = true; } bool Adafruit_FONA::incomingCallNumber(char* phonenum) { //+CLIP: "<incoming phone number>",145,"",0,"",0 if(!_incomingCall) return false; readline(); while(!strcmp(replybuffer, "RING") == 0) { flushInput(); readline(); } readline(); //reads incoming phone number line parseReply("+CLIP: \"", phonenum, '"'); #ifdef ADAFRUIT_FONA_DEBUG printf("Phone Number: %s\r\n", replybuffer); #endif _incomingCall = false; return true; } /********* SMS **********************************************************/ uint8_t Adafruit_FONA::getSMSInterrupt(void) { uint16_t reply; if (! sendParseReply("AT+CFGRI?", "+CFGRI: ", &reply) ) return 0; return reply; } bool Adafruit_FONA::setSMSInterrupt(uint8_t i) { return sendCheckReply("AT+CFGRI=", i, ok_reply); } int8_t Adafruit_FONA::getNumSMS(void) { uint16_t numsms; if (! sendCheckReply("AT+CMGF=1", ok_reply)) return -1; // ask how many sms are stored if (! sendParseReply("AT+CPMS?", "+CPMS: \"SM_P\",", &numsms) ) return -1; return numsms; } // Reading SMS's is a bit involved so we don't use helpers that may cause delays or debug // printouts! bool Adafruit_FONA::readSMS(uint8_t i, char *smsbuff, uint16_t maxlen, uint16_t *readlen) { // text mode if (! sendCheckReply("AT+CMGF=1", ok_reply)) return false; // show all text mode parameters if (! sendCheckReply("AT+CSDH=1", ok_reply)) return false; // parse out the SMS len uint16_t thesmslen = 0; //getReply(F("AT+CMGR="), i, 1000); // do not print debug! mySerial.printf("AT+CMGR=%d\r\n", i); readline(1000); // timeout // parse it out... if (! parseReply("+CMGR:", &thesmslen, ',', 11)) { *readlen = 0; return false; } readRaw(thesmslen); flushInput(); uint16_t thelen = min(maxlen, (uint16_t)strlen(replybuffer)); strncpy(smsbuff, replybuffer, thelen); smsbuff[thelen] = 0; // end the string #ifdef ADAFRUIT_FONA_DEBUG printf("%s\r\n", replybuffer); #endif *readlen = thelen; return true; } // Retrieve the sender of the specified SMS message and copy it as a string to // the sender buffer. Up to senderlen characters of the sender will be copied // and a null terminator will be added if less than senderlen charactesr are // copied to the result. Returns true if a result was successfully retrieved, // otherwise false. bool Adafruit_FONA::getSMSSender(uint8_t i, char *sender, int senderlen) { // Ensure text mode and all text mode parameters are sent. if (! sendCheckReply("AT+CMGF=1", ok_reply)) return false; if (! sendCheckReply("AT+CSDH=1", ok_reply)) return false; // Send command to retrieve SMS message and parse a line of response. mySerial.printf("AT+CMGR=%d\r\n", i); readline(1000); // Parse the second field in the response. bool result = parseReplyQuoted("+CMGR:", sender, senderlen, ',', 1); // Drop any remaining data from the response. flushInput(); return result; } bool Adafruit_FONA::sendSMS(char *smsaddr, char *smsmsg) { if (! sendCheckReply("AT+CMGF=1", ok_reply)) return -1; char sendcmd[30] = "AT+CMGS=\""; strncpy(sendcmd+9, smsaddr, 30-9-2); // 9 bytes beginning, 2 bytes for close quote + null sendcmd[strlen(sendcmd)] = '\"'; if (! sendCheckReply(sendcmd, "> ")) return false; #ifdef ADAFRUIT_FONA_DEBUG printf("> %s\r\n", smsmsg); #endif mySerial.printf("%s\r\n\r\n", smsmsg); mySerial.putc(0x1A); #ifdef ADAFRUIT_FONA_DEBUG printf("^Z\r\n"); #endif readline(10000); // read the +CMGS reply, wait up to 10 seconds!!! //Serial.print("* "); Serial.println(replybuffer); if (strstr(replybuffer, "+CMGS") == 0) { return false; } readline(1000); // read OK //Serial.print("* "); Serial.println(replybuffer); if (strcmp(replybuffer, ok_reply) != 0) { return false; } return true; } bool Adafruit_FONA::deleteSMS(uint8_t i) { if (! sendCheckReply("AT+CMGF=1", ok_reply)) return -1; // read an sms char sendbuff[12] = "AT+CMGD=000"; sendbuff[8] = (i / 100) + '0'; i %= 100; sendbuff[9] = (i / 10) + '0'; i %= 10; sendbuff[10] = i + '0'; return sendCheckReply(sendbuff, ok_reply, 2000); } /********* TIME **********************************************************/ bool Adafruit_FONA::enableNetworkTimeSync(bool onoff) { if (onoff) { if (! sendCheckReply("AT+CLTS=1", ok_reply)) return false; } else { if (! sendCheckReply("AT+CLTS=0", ok_reply)) return false; } flushInput(); // eat any 'Unsolicted Result Code' return true; } bool Adafruit_FONA::enableNTPTimeSync(bool onoff, const char* ntpserver) { if (onoff) { if (! sendCheckReply("AT+CNTPCID=1", ok_reply)) return false; mySerial.printf("AT+CNTP=\""); if (ntpserver != 0) { mySerial.printf(ntpserver); } else { mySerial.printf("pool.ntp.org"); } mySerial.printf("\",0\r\n"); readline(FONA_DEFAULT_TIMEOUT_MS); if (strcmp(replybuffer, ok_reply) != 0) return false; if (! sendCheckReply("AT+CNTP", ok_reply, 10000)) return false; uint16_t status; readline(10000); if (! parseReply("+CNTP:", &status)) return false; } else { if (! sendCheckReply("AT+CNTPCID=0", ok_reply)) return false; } return true; } bool Adafruit_FONA::getTime(char* buff, uint16_t maxlen) { getReply("AT+CCLK?", (uint16_t) 10000); if (strncmp(replybuffer, "+CCLK: ", 7) != 0) return false; char *p = replybuffer+7; uint16_t lentocopy = min((uint16_t)(maxlen-1), (uint16_t)strlen(p)); strncpy(buff, p, lentocopy+1); buff[lentocopy] = 0; readline(); // eat OK return true; } /********* GPS **********************************************************/ bool Adafruit_FONA::enableGPS(bool onoff) { uint16_t state; // first check if its already on or off if (! sendParseReply("AT+CGPSPWR?", "+CGPSPWR: ", &state) ) return false; if (onoff && !state) { if (! sendCheckReply("AT+CGPSPWR=1", ok_reply)) return false; } else if (!onoff && state) { if (! sendCheckReply("AT+CGPSPWR=0", ok_reply)) return false; } return true; } bool Adafruit_FONA_3G::enableGPS(bool onoff) { uint16_t state; // first check if its already on or off if (! Adafruit_FONA::sendParseReply("AT+CGPS?", "+CGPS: ", &state) ) return false; if (onoff && !state) { if (! sendCheckReply("AT+CGPS=1", ok_reply)) return false; } else if (!onoff && state) { if (! sendCheckReply("AT+CGPS=0", ok_reply)) return false; // this takes a little time readline(2000); // eat '+CGPS: 0' } return true; } int8_t Adafruit_FONA::GPSstatus(void) { getReply("AT+CGPSSTATUS?"); char *p = strstr(replybuffer, "+CGPSSTATUS: Location "); if (p == 0) return -1; p+=22; readline(); // eat 'OK' if (p[0] == 'U') return 0; if (p[0] == 'N') return 1; if (p[0] == '2') return 2; if (p[0] == '3') return 3; // else return 0; } uint8_t Adafruit_FONA::getGPS(uint8_t arg, char *buffer, uint8_t maxbuff) { int32_t x = arg; getReply("AT+CGPSINF=", x); char *p = strstr(replybuffer, "CGPSINF: "); if (p == 0) { buffer[0] = 0; return 0; } p+=9; uint8_t len = max((uint8_t)(maxbuff-1), (uint8_t)strlen(p)); strncpy(buffer, p, len); buffer[len] = 0; readline(); // eat 'OK' return len; } bool Adafruit_FONA::getGPS(float *lat, float *lon, float *speed_kph, float *heading, float *altitude) { char gpsbuffer[120]; // we need at least a 2D fix if (GPSstatus() < 2) return false; // grab the mode 2^5 gps csv from the sim808 uint8_t res_len = getGPS(32, gpsbuffer, 120); // make sure we have a response if (res_len == 0) return false; // skip mode char *tok = strtok(gpsbuffer, ","); if (! tok) return false; // skip date tok = strtok(NULL, ","); if (! tok) return false; // skip fix tok = strtok(NULL, ","); if (! tok) return false; // grab the latitude char *latp = strtok(NULL, ","); if (! latp) return false; // grab latitude direction char *latdir = strtok(NULL, ","); if (! latdir) return false; // grab longitude char *longp = strtok(NULL, ","); if (! longp) return false; // grab longitude direction char *longdir = strtok(NULL, ","); if (! longdir) return false; double latitude = atof(latp); double longitude = atof(longp); // convert latitude from minutes to decimal float degrees = floor(latitude / 100); double minutes = latitude - (100 * degrees); minutes /= 60; degrees += minutes; // turn direction into + or - if (latdir[0] == 'S') degrees *= -1; *lat = degrees; // convert longitude from minutes to decimal degrees = floor(longitude / 100); minutes = longitude - (100 * degrees); minutes /= 60; degrees += minutes; // turn direction into + or - if (longdir[0] == 'W') degrees *= -1; *lon = degrees; // only grab speed if needed if (speed_kph != NULL) { // grab the speed in knots char *speedp = strtok(NULL, ","); if (! speedp) return false; // convert to kph *speed_kph = atof(speedp) * 1.852; } // only grab heading if needed if (heading != NULL) { // grab the speed in knots char *coursep = strtok(NULL, ","); if (! coursep) return false; *heading = atof(coursep); } // no need to continue if (altitude == NULL) return true; // we need at least a 3D fix for altitude if (GPSstatus() < 3) return false; // grab the mode 0 gps csv from the sim808 res_len = getGPS(0, gpsbuffer, 120); // make sure we have a response if (res_len == 0) return false; // skip mode tok = strtok(gpsbuffer, ","); if (! tok) return false; // skip lat tok = strtok(NULL, ","); if (! tok) return false; // skip long tok = strtok(NULL, ","); if (! tok) return false; // grab altitude char *altp = strtok(NULL, ","); if (! altp) return false; *altitude = atof(altp); return true; } bool Adafruit_FONA::enableGPSNMEA(uint8_t i) { char sendbuff[15] = "AT+CGPSOUT=000"; sendbuff[11] = (i / 100) + '0'; i %= 100; sendbuff[12] = (i / 10) + '0'; i %= 10; sendbuff[13] = i + '0'; return sendCheckReply(sendbuff, ok_reply, 2000); } /********* GPRS **********************************************************/ bool Adafruit_FONA::enableGPRS(bool onoff) { if (onoff) { // disconnect all sockets sendCheckReply("AT+CIPSHUT", "SHUT OK", 5000); if (! sendCheckReply("AT+CGATT=1", ok_reply, 10000)) return false; // set bearer profile! connection type GPRS if (! sendCheckReply("AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"", ok_reply, 10000)) return false; // set bearer profile access point name if (apn) { // Send command AT+SAPBR=3,1,"APN","<apn value>" where <apn value> is the configured APN value. if (! sendCheckReplyQuoted("AT+SAPBR=3,1,\"APN\",", apn, ok_reply, 10000)) return false; // set username/password if (apnusername) { // Send command AT+SAPBR=3,1,"USER","<user>" where <user> is the configured APN username. if (! sendCheckReplyQuoted("AT+SAPBR=3,1,\"USER\",", apnusername, ok_reply, 10000)) return false; } if (apnpassword) { // Send command AT+SAPBR=3,1,"PWD","<password>" where <password> is the configured APN password. if (! sendCheckReplyQuoted("AT+SAPBR=3,1,\"PWD\",", apnpassword, ok_reply, 10000)) return false; } } // open GPRS context if (! sendCheckReply("AT+SAPBR=1,1", ok_reply, 10000)) return false; } else { // disconnect all sockets if (! sendCheckReply("AT+CIPSHUT", "SHUT OK", 5000)) return false; // close GPRS context if (! sendCheckReply("AT+SAPBR=0,1", ok_reply, 10000)) return false; if (! sendCheckReply("AT+CGATT=0", ok_reply, 10000)) return false; } return true; } int Adafruit_FONA::GPRSstate(void) { uint16_t state; if (! sendParseReply("AT+CGATT?", "+CGATT: ", &state) ) return -1; return state; } void Adafruit_FONA::setGPRSNetworkSettings(const char* apn, const char* ausername, const char* apassword) { this->apn = (char*) apn; this->apnusername = (char*) ausername; this->apnpassword = (char*) apassword; } bool Adafruit_FONA::getGSMLoc(uint16_t *errorcode, char *buff, uint16_t maxlen) { getReply("AT+CIPGSMLOC=1,1", (uint16_t)10000); if (! parseReply("+CIPGSMLOC: ", errorcode)) return false; char *p = replybuffer+14; uint16_t lentocopy = min((uint16_t)(maxlen-1), (uint16_t)strlen(p)); strncpy(buff, p, lentocopy+1); readline(); // eat OK return true; } bool Adafruit_FONA::getGSMLoc(float *lat, float *lon) { uint16_t returncode; char gpsbuffer[120]; // make sure we could get a response if (! getGSMLoc(&returncode, gpsbuffer, 120)) return false; // make sure we have a valid return code if (returncode != 0) return false; // tokenize the gps buffer to locate the lat & long char *latp = strtok(gpsbuffer, ","); if (! latp) return false; char *longp = strtok(NULL, ","); if (! longp) return false; *lat = atof(latp); *lon = atof(longp); return true; } /********* TCP FUNCTIONS ************************************/ uint8_t Adafruit_FONA_3G::TCPinitialize(void) { // AT+CGDCONT=1,"IP","orange-mib" AT+CGDCONT? N/A // if (! sendCheckReply("AT+CGDCONT=1,\"IP\",\"orange-mib\"", ok_reply, 5000)) return 1; // AT+CMMSPROTO=1,"172.16.2.8",8000 N/A // if (! sendCheckReply("AT+CMMSPROTO=1,\"172.16.2.8\",8000", ok_reply, 5000)) return 2; // AT+CREG=1 AT+CREG? OK if (! sendCheckReply("AT+CREG=1", ok_reply, 500)) return 3; // AT+CGSOCKCONT=1,"IP","orange-mib" N/A // if (! sendCheckReply("AT+CGSOCKCONT=1,\"IP\",\"orange-mib\"", ok_reply, 5000)) return 4; // AT+CSOCKSETPN=1 AT+CSOCKSETPN? N/A if (! sendCheckReply("AT+CSOCKSETPN=1", ok_reply, 5000)) return 5; // AT+CGAUTH=1,2,"orange","orange" AT+CGAUTH? N/A // if (! sendCheckReply("AT+CGAUTH=1,2,\"orange\",\"orange\"", ok_reply, 5000)) return 6; // AT+CSOCKAUTH=1,2,"orange","orange" AT+CSOCKAUTH? N/A // if (! sendCheckReply("AT+CSOCKAUTH=1,2,\"orange\",\"orange\"", ok_reply, 5000)) return 7; // AT+CIPMODE=1 AT+CIPMODE? OK if (! sendCheckReply("AT+CIPMODE=1", ok_reply, 5000)) return 8; // ATS0=007 ATS0? OK if (! sendCheckReply("ATS0=007", ok_reply, 5000)) return 9; // AT+CGATT=1 AT+CGATT? N/A if (! sendCheckReply("AT+CGATT=1", ok_reply, 5000)) return 10; // AT+CGACT=1,1 AT+CGACT? OK if (! sendCheckReply("AT+CGACT=1,1", ok_reply, 5000)) return 11; // AT+NETOPEN OK if (! sendCheckReply("AT+NETOPEN", ok_reply, 5000)) return 12; wait_ms(5000); return 0; } uint8_t Adafruit_FONA_3G::sslTCPinitialize(void) { // start common channel if (! sendCheckReply("AT+CCHSTART", ok_reply, 3000) ) return 1; if (! expectReply("+CCHSTART: 0")) return 2; return 0; } uint8_t Adafruit_FONA_3G::getTCPtimeout(char *tcptimeout) { getReply("AT+CIPTIMEOUT?"); // up to 28 chars for reply, 20 char total tcptimeout if (replybuffer[0] == '+') { // fona 3g? strncpy(tcptimeout, replybuffer+12, 20); } else { // fona 800 or 800 strncpy(tcptimeout, replybuffer, 20); } tcptimeout[20] = 0; readline(); // eat 'OK' return strlen(tcptimeout); } bool Adafruit_FONA::TCPconnect(char *server, uint16_t port) { flushInput(); // close all old connections if (! sendCheckReply("AT+CIPSHUT", "SHUT OK", 5000) ) return false; // single connection at a time if (! sendCheckReply("AT+CIPMUX=0", ok_reply) ) return false; // manually read data if (! sendCheckReply("AT+CIPRXGET=1", ok_reply) ) return false; #ifdef ADAFRUIT_FONA_DEBUG printf("AT+CIPSTART=\"TCP\",\"%s\",\"%d\"\r\n", server, port); #endif mySerial.printf("AT+CIPSTART=\"TCP\",\"%s\",\"%d\"\r\n", server, port); if (! expectReply(ok_reply)) return false; if (! expectReply("CONNECT OK")) return false; return true; } bool Adafruit_FONA_3G::TCPconnect(char *server, uint16_t port) { flushInput(); #ifdef ADAFRUIT_FONA_DEBUG printf("AT+CIPOPEN=0,\"TCP\",\"%s\",%d\r\n", server, port); #endif mySerial.printf("AT+CIPOPEN=0,\"TCP\",\"%s\",%d\r\n", server, port); if (! expectReply("CONNECT 4800")) return false; return true; } bool Adafruit_FONA_3G::sslTCPconnect(char *server, uint16_t port) { flushInput(); #ifdef ADAFRUIT_FONA_DEBUG printf("AT+CCHOPEN=0,\"%s\",%d,2\r\n", server, port); #endif mySerial.printf("AT+CCHOPEN=0,\"%s\",%d,2\r\n", server, port); if (! expectReply(ok_reply)) return false; if (! expectReply("+CCHOPEN: 0,0")) return false; if (! expectReply("+CCHRECV: DATA,0,10", 10000)) return false; readline(); return true; } uint8_t Adafruit_FONA::getIPADDR(char *ipaddr) { getReply("AT+IPADDR"); // up to 28 chars for reply, 20 char total ipaddr if (replybuffer[0] == '+') { // fona 3g? strncpy(ipaddr, replybuffer+8, 20); } else { // fona 800 or 800 strncpy(ipaddr, replybuffer, 20); } ipaddr[20] = 0; readline(); // eat 'OK' return strlen(ipaddr); } bool Adafruit_FONA::TCPclose(void) { return sendCheckReply("AT+CIPCLOSE", ok_reply); } bool Adafruit_FONA_3G::TCPclose(void) { return sendCheckReply("AT+CIPCLOSE=0", ok_reply); } bool Adafruit_FONA_3G::sslTCPclose(void) { return sendCheckReply("AT+CCHCLOSE=0", ok_reply); } bool Adafruit_FONA::TCPconnected(void) { if (! sendCheckReply("AT+CIPSTATUS", ok_reply, 100) ) return false; readline(100); #ifdef ADAFRUIT_FONA_DEBUG printf("\t<--- %s\r\n", replybuffer); #endif return (strcmp(replybuffer, "STATE: CONNECT OK") == 0); } bool Adafruit_FONA::TCPsend(char *packet, uint8_t len) { #ifdef ADAFRUIT_FONA_DEBUG printf("AT+CIPSEND=%d\r\n", len); for (uint16_t i=0; i<len; i++) { printf(" 0x%#02x", packet[i]); } printf("\r\n"); #endif mySerial.printf("AT+CIPSEND=%d\r\n", len); readline(); #ifdef ADAFRUIT_FONA_DEBUG printf("\t<--- %s\r\n", replybuffer); #endif if (replybuffer[0] != '>') return false; for (uint16_t i=0; i<len; i++) { mySerial.putc(packet[i]); } readline(3000); // wait up to 3 seconds to send the data #ifdef ADAFRUIT_FONA_DEBUG printf("\t<--- %s\r\n", replybuffer); #endif return (strcmp(replybuffer, "SEND OK") == 0); } bool Adafruit_FONA_3G::TCPsend(char *packet) { if (strlen(packet) > 0) { mySerial.printf("%s", packet); //mySerial.printf("%s\r\n", packet); readline(); packet[0] = 0; return true; } else return false; } bool Adafruit_FONA_3G::sslTCPsend(char *packet) { if (strlen(packet) > 0) { mySerial.printf("AT+CCHSEND=0,%d\r\n", strlen(packet)); readline(); #ifdef ADAFRUIT_FONA_DEBUG printf("\t<--- %s\r\n", replybuffer); #endif if (replybuffer[0] != '>') return false; for (uint16_t i=0; i<strlen(packet); i++) { mySerial.putc(packet[i]); } packet[0] = 0; #ifdef ADAFRUIT_FONA_DEBUG printf("\t<--- %s\r\n", replybuffer); #endif return true; } else return false; } uint16_t Adafruit_FONA::TCPavailable(void) { uint16_t avail; if (! sendParseReply("AT+CIPRXGET=4", "+CIPRXGET: 4,", &avail, ',', 0) ) return false; #ifdef ADAFRUIT_FONA_DEBUG printf("%d bytes available\r\n", avail); #endif return avail; } uint16_t Adafruit_FONA::TCPread(uint8_t *buff, uint8_t len) { uint16_t avail; mySerial.printf("AT+CIPRXGET=2,%d\r\n", len); readline(); if (! parseReply("+CIPRXGET: 2,", &avail, ',', 0)) return false; readRaw(avail); #ifdef ADAFRUIT_FONA_DEBUG printf("%d bytes read\r\n", avail); for (uint8_t i=0; i<avail; i++) { printf(" 0x%#02x", replybuffer[i]); } printf("\r\n"); #endif readline(); memcpy(buff, replybuffer, avail); return avail; } uint16_t Adafruit_FONA_3G::sslTCPread(char *buff) { uint16_t avail; readline(); if (! parseReply("+CCHRECV: DATA,", &avail, ',', 1)) return false; readRaw(avail); #ifdef ADAFRUIT_FONA_DEBUG printf("%d bytes read\r\n", avail); for (uint8_t i=0; i<avail; i++) { printf("%c", replybuffer[i]); } printf("\r\n"); #endif memcpy(buff, replybuffer, avail); buff[avail] = 0; return avail; } /********* HTTP LOW LEVEL FUNCTIONS ************************************/ bool Adafruit_FONA::HTTP_init() { return sendCheckReply("AT+HTTPINIT", ok_reply); } bool Adafruit_FONA::HTTP_term() { return sendCheckReply("AT+HTTPTERM", ok_reply); } void Adafruit_FONA::HTTP_para_start(const char* parameter, bool quoted) { flushInput(); #ifdef ADAFRUIT_FONA_DEBUG printf("\t---> AT+HTTPPARA=\"%s\"\r\n", parameter); #endif mySerial.printf("AT+HTTPPARA=\"%s", parameter); if (quoted) mySerial.printf("\",\""); else mySerial.printf("\","); } bool Adafruit_FONA::HTTP_para_end(bool quoted) { if (quoted) mySerial.printf("\"\r\n"); else mySerial.printf("\r\n"); return expectReply(ok_reply); } bool Adafruit_FONA::HTTP_para(const char* parameter, const char* value) { HTTP_para_start(parameter, true); mySerial.printf(value); return HTTP_para_end(true); } bool Adafruit_FONA::HTTP_para(const char* parameter, int32_t value) { HTTP_para_start(parameter, false); mySerial.printf("%d", value); return HTTP_para_end(false); } bool Adafruit_FONA::HTTP_data(uint32_t size, uint32_t maxTime) { flushInput(); #ifdef ADAFRUIT_FONA_DEBUG printf("\t---> AT+HTTPDATA=%d,%d\r\n", size, maxTime); #endif mySerial.printf("AT+HTTPDATA=%d,%d\r\n", size, maxTime); return expectReply("DOWNLOAD"); } bool Adafruit_FONA::HTTP_action(uint8_t method, uint16_t *status, uint16_t *datalen, int32_t timeout) { // Send request. if (! sendCheckReply("AT+HTTPACTION=", method, ok_reply)) return false; // Parse response status and size. readline(timeout); if (! parseReply("+HTTPACTION:", status, ',', 1)) return false; if (! parseReply("+HTTPACTION:", datalen, ',', 2)) return false; return true; } bool Adafruit_FONA::HTTP_readall(uint16_t *datalen) { getReply("AT+HTTPREAD"); if (! parseReply("+HTTPREAD:", datalen, ',', 0)) return false; return true; } bool Adafruit_FONA::HTTP_ssl(bool onoff) { return sendCheckReply("AT+HTTPSSL=", onoff ? 1 : 0, ok_reply); } /********* HTTP HIGH LEVEL FUNCTIONS ***************************/ bool Adafruit_FONA::HTTP_GET_start(char *url, uint16_t *status, uint16_t *datalen) { if (! HTTP_setup(url)) return false; // HTTP GET if (! HTTP_action(FONA_HTTP_GET, status, datalen)) return false; #ifdef ADAFRUIT_FONA_DEBUG printf("Status: %d\r\n", *status); printf("Len: %d\r\n", *datalen); #endif // HTTP response data if (! HTTP_readall(datalen)) return false; return true; } void Adafruit_FONA::HTTP_GET_end(void) { HTTP_term(); } bool Adafruit_FONA::HTTP_POST_start(char *url, const char* contenttype, const uint8_t *postdata, uint16_t postdatalen, uint16_t *status, uint16_t *datalen) { if (! HTTP_setup(url)) return false; if (! HTTP_para("CONTENT", contenttype)) { return false; } // HTTP POST data if (! HTTP_data(postdatalen, 10000)) return false; for (uint16_t i = 0; i < postdatalen; i++) { mySerial.putc(postdata[i]); } if (! expectReply(ok_reply)) return false; // HTTP POST if (! HTTP_action(FONA_HTTP_POST, status, datalen)) return false; #ifdef ADAFRUIT_FONA_DEBUG printf("Status: %d\r\n", *status); printf("Len: %d\r\n", *datalen); #endif // HTTP response data if (! HTTP_readall(datalen)) return false; return true; } void Adafruit_FONA::HTTP_POST_end(void) { HTTP_term(); } void Adafruit_FONA::setUserAgent(const char* useragent) { this->useragent = (char*) useragent; } void Adafruit_FONA::setHTTPSRedirect(bool onoff) { httpsredirect = onoff; } /********* HTTP HELPERS ****************************************/ bool Adafruit_FONA::HTTP_setup(char *url) { // Handle any pending HTTP_term(); // Initialize and set parameters if (! HTTP_init()) return false; if (! HTTP_para("CID", 1)) return false; if (! HTTP_para("UA", useragent)) return false; if (! HTTP_para("URL", url)) return false; // HTTPS redirect if (httpsredirect) { if (! HTTP_para("REDIR",1)) return false; if (! HTTP_ssl(true)) return false; } return true; } /********* HELPERS *********************************************/ bool Adafruit_FONA::expectReply(const char* reply, uint16_t timeout) { readline(timeout); #ifdef ADAFRUIT_FONA_DEBUG printf("\t<--- %s\r\n", replybuffer); #endif return (strcmp(replybuffer, reply) == 0); } /********* LOW LEVEL *******************************************/ void Adafruit_FONA::flushInput() { // Read all available serial input to flush pending data. uint16_t timeoutloop = 0; while (timeoutloop++ < 400) { while(readable()) { getc(); timeoutloop = 0; // If char was received reset the timer } wait_ms(1); } } uint16_t Adafruit_FONA::readRaw(uint16_t b) { uint16_t idx = 0; // && (idx < sizeof(replybuffer)-1) while (b && idx < 255) { if (readable()) { replybuffer[idx] = getc(); idx++; b--; } } replybuffer[idx] = 0; return idx; } uint8_t Adafruit_FONA::readline(uint16_t timeout, bool multiline) { uint16_t replyidx = 0; while (timeout--) { if (replyidx >= 254) { break; } while(readable()) { char c = getc(); if (c == '\r') continue; if (c == 0x0A) { if (replyidx == 0) // the first 0x0A is ignored continue; if (!multiline) { timeout = 0; // the second 0x0A is the end of the line break; } } replybuffer[replyidx] = c; replyidx++; } if (timeout == 0) { break; } wait_ms(1); } replybuffer[replyidx] = 0; // null term return replyidx; } uint8_t Adafruit_FONA::getReply(const char* send, uint16_t timeout) { flushInput(); #ifdef ADAFRUIT_FONA_DEBUG printf("\t---> %s\r\n", send); #endif mySerial.printf("%s\r\n",send); uint8_t l = readline(timeout); #ifdef ADAFRUIT_FONA_DEBUG printf("\t<--- %s\r\n", replybuffer); #endif return l; } // Send prefix, suffix, and newline. Return response (and also set replybuffer with response). uint8_t Adafruit_FONA::getReply(const char* prefix, char* suffix, uint16_t timeout) { flushInput(); #ifdef ADAFRUIT_FONA_DEBUG printf("\t---> %s%s\r\n", prefix, suffix); #endif mySerial.printf("%s%s\r\n", prefix, suffix); uint8_t l = readline(timeout); #ifdef ADAFRUIT_FONA_DEBUG printf("\t<--- %s\r\n", replybuffer); #endif return l; } // Send prefix, suffix, and newline. Return response (and also set replybuffer with response). uint8_t Adafruit_FONA::getReply(const char* prefix, int32_t suffix, uint16_t timeout) { flushInput(); #ifdef ADAFRUIT_FONA_DEBUG printf("\t---> %s%d\r\n", prefix, suffix); #endif mySerial.printf("%s%d\r\n", prefix, suffix); uint8_t l = readline(timeout); #ifdef ADAFRUIT_FONA_DEBUG printf("\t<--- %s\r\n", replybuffer); #endif return l; } // Send prefix, suffix, suffix2, and newline. Return response (and also set replybuffer with response). uint8_t Adafruit_FONA::getReply(const char* prefix, int32_t suffix1, int32_t suffix2, uint16_t timeout) { flushInput(); #ifdef ADAFRUIT_FONA_DEBUG printf("\t---> %s%d,%d\r\n", prefix, suffix1, suffix2); #endif mySerial.printf("%s%d,%d\r\n", prefix, suffix1, suffix2); uint8_t l = readline(timeout); #ifdef ADAFRUIT_FONA_DEBUG printf("\t<--- %s\r\n", replybuffer); #endif return l; } // Send prefix, ", suffix, ", and newline. Return response (and also set replybuffer with response). uint8_t Adafruit_FONA::getReplyQuoted(const char* prefix, const char* suffix, uint16_t timeout) { flushInput(); #ifdef ADAFRUIT_FONA_DEBUG printf("\t---> %s\"%s\"\r\n", prefix, suffix); #endif mySerial.printf("%s\"%s\"\r\n", prefix, suffix); uint8_t l = readline(timeout); #ifdef ADAFRUIT_FONA_DEBUG printf("\t<--- %s\r\n", replybuffer); #endif return l; } bool Adafruit_FONA::sendCheckReply(const char *send, const char *reply, uint16_t timeout) { if (! getReply(send, timeout)) return false; return (strcmp(replybuffer, reply) == 0); } // Send prefix, suffix, and newline. Verify FONA response matches reply parameter. bool Adafruit_FONA::sendCheckReply(const char* prefix, char *suffix, const char* reply, uint16_t timeout) { if (! getReply(prefix, suffix, timeout)) return false; return (strcmp(replybuffer, reply) == 0); } // Send prefix, suffix, and newline. Verify FONA response matches reply parameter. bool Adafruit_FONA::sendCheckReply(const char* prefix, int32_t suffix, const char* reply, uint16_t timeout) { if (! getReply(prefix, suffix, timeout)) return false; return (strcmp(replybuffer, reply) == 0); } // Send prefix, suffix, suffix2, and newline. Verify FONA response matches reply parameter. bool Adafruit_FONA::sendCheckReply(const char* prefix, int32_t suffix1, int32_t suffix2, const char* reply, uint16_t timeout) { getReply(prefix, suffix1, suffix2, timeout); return (strcmp(replybuffer, reply) == 0); } // Send prefix, ", suffix, ", and newline. Verify FONA response matches reply parameter. bool Adafruit_FONA::sendCheckReplyQuoted(const char* prefix, const char* suffix, const char* reply, uint16_t timeout) { getReplyQuoted(prefix, suffix, timeout); return (strcmp(replybuffer, reply) == 0); } bool Adafruit_FONA::parseReply(const char* toreply, uint32_t *v, char divider, uint8_t index) { char *p = strstr(replybuffer, toreply); // get the pointer to the voltage if (p == 0) return false; p += strlen(toreply); for (uint8_t i=0; i<index; i++) { // increment dividers p = strchr(p, divider); if (!p) return false; p++; } *v = atoi(p); return true; } bool Adafruit_FONA::parseReply(const char* toreply, uint16_t *v, char divider, uint8_t index) { char *p = strstr(replybuffer, toreply); // get the pointer to the voltage if (p == 0) return false; p += strlen(toreply); for (uint8_t i=0; i<index; i++) { // increment dividers p = strchr(p, divider); if (!p) return false; p++; } *v = atoi(p); return true; } bool Adafruit_FONA::parseReply(const char* toreply, char *v, char divider, uint8_t index) { uint8_t i=0; char *p = strstr(replybuffer, toreply); if (p == 0) return false; p+=strlen(toreply); for (i=0; i<index; i++) { // increment dividers p = strchr(p, divider); if (!p) return false; p++; } for(i=0; i<strlen(p); i++) { if(p[i] == divider) break; v[i] = p[i]; } v[i] = '\0'; return true; } // Parse a quoted string in the response fields and copy its value (without quotes) // to the specified character array (v). Only up to maxlen characters are copied // into the result buffer, so make sure to pass a large enough buffer to handle the // response. bool Adafruit_FONA::parseReplyQuoted(const char* toreply, char* v, int maxlen, char divider, uint8_t index) { uint8_t i=0, j; // Verify response starts with toreply. char *p = strstr(replybuffer, toreply); if (p == 0) return false; p+=strlen(toreply); // Find location of desired response field. for (i=0; i<index; i++) { // increment dividers p = strchr(p, divider); if (!p) return false; p++; } // Copy characters from response field into result string. for(i=0, j=0; j<maxlen && i<strlen(p); ++i) { // Stop if a divier is found. if(p[i] == divider) break; // Skip any quotation marks. else if(p[i] == '"') continue; v[j++] = p[i]; } // Add a null terminator if result string buffer was not filled. if (j < maxlen) v[j] = '\0'; return true; } bool Adafruit_FONA::sendParseReply(const char* tosend, const char* toreply, uint32_t *v, char divider, uint8_t index) { getReply(tosend); if (! parseReply(toreply, v, divider, index)) return false; readline(); // eat 'OK' return true; } bool Adafruit_FONA::sendParseReply(const char* tosend, const char* toreply, uint16_t *v, char divider, uint8_t index) { getReply(tosend); if (! parseReply(toreply, v, divider, index)) return false; readline(); // eat 'OK' return true; } // needed for CBC and others bool Adafruit_FONA_3G::sendParseReply(const char* tosend, const char* toreply, float *f, char divider, uint8_t index) { getReply(tosend); if (! parseReply(toreply, f, divider, index)) return false; readline(); // eat 'OK' return true; } bool Adafruit_FONA_3G::parseReply(const char* toreply, uint16_t *v, char divider, uint8_t index) { char *p = strstr(replybuffer, toreply); // get the pointer to the voltage if (p == 0) return false; p += strlen(toreply); for (uint8_t i=0; i<index; i++) { // increment dividers p = strchr(p, divider); if (!p) return false; p++; } *v = atoi(p); return true; } bool Adafruit_FONA_3G::parseReply(const char* toreply, float *f, char divider, uint8_t index) { char *p = strstr(replybuffer, toreply); // get the pointer to the voltage if (p == 0) return false; p+=strlen(toreply); //DEBUG_PRINTLN(p); for (uint8_t i=0; i<index; i++) { // increment dividers p = strchr(p, divider); if (!p) return false; p++; //DEBUG_PRINTLN(p); } *f = atof(p); return true; }