Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of Adafruit_FONA_Library by
Adafruit_FONA.cpp
- Committer:
- marcpl
- Date:
- 2015-06-27
- Revision:
- 0:d567815b7a5f
- Child:
- 1:89299f09929c
File content as of revision 0:d567815b7a5f:
/***************************************************
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
*/
#include <algorithm>
#include "Adafruit_FONA.h"
#define HIGH 1
#define LOW 0
bool Adafruit_FONA::begin(Serial &port) {
mySerial = &port;
_rstpin = HIGH;
wait_ms(10);
_rstpin = LOW;
wait_ms(100);
_rstpin = HIGH;
// give 3 seconds to reboot
wait_ms(3000);
while (mySerial->readable()) mySerial->getc();
sendCheckReply("AT", "OK");
wait_ms(100);
sendCheckReply("AT", "OK");
wait_ms(100);
sendCheckReply("AT", "OK");
wait_ms(100);
// turn off Echo!
sendCheckReply("ATE0", "OK");
wait_ms(100);
if (! sendCheckReply("ATE0", "OK")) {
return false;
}
return true;
}
/********* Real Time Clock ********************************************/
bool Adafruit_FONA::enableRTC(uint8_t i) {
if (! sendCheckReply("AT+CLTS=", i, "OK"))
return false;
return sendCheckReply("AT&W", "OK");
}
/********* BATTERY & ADC ********************************************/
/* returns value in mV (uint16_t) */
bool Adafruit_FONA::getBattVoltage(uint16_t *v) {
return sendParseReply("AT+CBC", "+CBC: ", v, ',', 2);
}
/* 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)
{
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");
}
uint8_t Adafruit_FONA::getSIMCCID(char *ccid) {
getReply("AT+CCID");
// up to 20 chars
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");
}
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");
}
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");
}
bool Adafruit_FONA::playToolkitTone(uint8_t t, uint16_t len) {
return sendCheckReply("AT+STTONE=1,", t, len, "OK");
}
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");
}
/********* FM RADIO *******************************************************/
bool Adafruit_FONA::FMradio(bool onoff, uint8_t a) {
if (! onoff) {
return sendCheckReply("AT+FMCLOSE", "OK");
}
// 0 is headset, 1 is external audio
if (a > 1) return false;
return sendCheckReply("AT+FMOPEN=", a, "OK");
}
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");
}
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");
}
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");
}
/********* 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");
}
bool Adafruit_FONA::hangUp(void) {
return sendCheckReply("ATH0", "OK");
}
bool Adafruit_FONA::pickUp(void) {
return sendCheckReply("ATA", "OK");
}
void Adafruit_FONA::onIncomingCall() {
#ifdef ADAFRUIT_FONA_DEBUG
printf("> Incoming call...\r\n");
#endif
_incomingCall = true;
}
bool Adafruit_FONA::callerIdNotification(bool enable) {
if(enable){
_ringIndicatorInterruptIn.fall(this, &Adafruit_FONA::onIncomingCall);
return sendCheckReply("AT+CLIP=1", "OK");
}
_ringIndicatorInterruptIn.fall(NULL);
return sendCheckReply("AT+CLIP=0", "OK");
}
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");
}
int8_t Adafruit_FONA::getNumSMS(void) {
uint16_t numsms;
if (! sendCheckReply("AT+CMGF=1", "OK")) 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")) return false;
// show all text mode parameters
if (! sendCheckReply("AT+CSDH=1", "OK")) 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")) return false;
if (! sendCheckReply("AT+CSDH=1", "OK")) 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")) 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") != 0) {
return false;
}
return true;
}
bool Adafruit_FONA::deleteSMS(uint8_t i) {
if (! sendCheckReply("AT+CMGF=1", "OK")) 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", 2000);
}
/********* TIME **********************************************************/
bool Adafruit_FONA::enableNetworkTimeSync(bool onoff) {
if (onoff) {
if (! sendCheckReply("AT+CLTS=1", "OK"))
return false;
} else {
if (! sendCheckReply("AT+CLTS=0", "OK"))
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"))
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") != 0)
return false;
if (! sendCheckReply("AT+CNTP", "OK", 10000))
return false;
uint16_t status;
readline(10000);
if (! parseReply("+CNTP:", &status))
return false;
} else {
if (! sendCheckReply("AT+CNTPCID=0", "OK"))
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"))
return false;
} else if (!onoff && state) {
if (! sendCheckReply("AT+CGPSPWR=0", "OK"))
return false;
}
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", 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", 10000))
return false;
// set bearer profile! connection type GPRS
if (! sendCheckReply("AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"", "OK", 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", 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", 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", 10000))
return false;
}
}
// open GPRS context
if (! sendCheckReply("AT+SAPBR=1,1", "OK", 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", 10000))
return false;
if (! sendCheckReply("AT+CGATT=0", "OK", 10000))
return false;
}
return true;
}
uint8_t 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 ************************************/
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") ) return false;
// manually read data
if (! sendCheckReply("AT+CIPRXGET=1", "OK") ) 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")) return false;
if (! expectReply("CONNECT OK")) return false;
return true;
}
bool Adafruit_FONA::TCPclose(void) {
return sendCheckReply("AT+CIPCLOSE", "OK");
}
bool Adafruit_FONA::TCPconnected(void) {
if (! sendCheckReply("AT+CIPSTATUS", "OK", 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);
}
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
memcpy(buff, replybuffer, avail);
return avail;
}
/********* HTTP LOW LEVEL FUNCTIONS ************************************/
bool Adafruit_FONA::HTTP_init() {
return sendCheckReply("AT+HTTPINIT", "OK");
}
bool Adafruit_FONA::HTTP_term() {
return sendCheckReply("AT+HTTPTERM", "OK");
}
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");
}
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"))
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");
}
/********* 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"))
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++ < 40) {
while(mySerial->readable()) {
mySerial->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;
while (b && (idx < sizeof(replybuffer)-1)) {
if (mySerial->readable()) {
replybuffer[idx] = mySerial->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(mySerial->readable()) {
char c = mySerial->getc();
if (c == '\r') continue;
if (c == 0xA) {
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) {
getReply(send, timeout);
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) {
getReply(prefix, suffix, timeout);
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) {
getReply(prefix, suffix, timeout);
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, 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, uint16_t *v, char divider, uint8_t index) {
getReply(tosend);
if (! parseReply(toreply, v, divider, index)) return false;
readline(); // eat 'OK'
return true;
}
