diff --git a/libraries/Adafruit_FONA_Library/.travis.yml b/libraries/Adafruit_FONA_Library/.travis.yml new file mode 100644 index 0000000..6b62611 --- /dev/null +++ b/libraries/Adafruit_FONA_Library/.travis.yml @@ -0,0 +1,10 @@ +language: c +sudo: false +before_install: + - source <(curl -SLs https://raw.githubusercontent.com/adafruit/travis-ci-arduino/master/install.sh) +script: + - build_main_platforms +notifications: + email: + on_success: change + on_failure: change diff --git a/libraries/Adafruit_FONA_Library/Adafruit_FONA.cpp b/libraries/Adafruit_FONA_Library/Adafruit_FONA.cpp new file mode 100644 index 0000000..714aa2f --- /dev/null +++ b/libraries/Adafruit_FONA_Library/Adafruit_FONA.cpp @@ -0,0 +1,1975 @@ +/*************************************************** + 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 + ****************************************************/ +#include + // next line per http://postwarrior.com/arduino-ethershield-error-prog_char-does-not-name-a-type/ +#define prog_char char PROGMEM + +#if (ARDUINO >= 100) + #include "Arduino.h" + #ifndef __SAM3X8E__ // Arduino Due doesn't support SoftwareSerial + #include + #endif +#else + #include "WProgram.h" + #include +#endif + +#include "Adafruit_FONA.h" + +Adafruit_FONA::Adafruit_FONA(int8_t rst) +{ + _rstpin = rst; + + apn = F("FONAnet"); + apnusername = 0; + apnpassword = 0; + mySerial = 0; + httpsredirect = false; + useragent = F("FONA"); +} + +uint8_t Adafruit_FONA::type(void) { + return _type; +} + +boolean Adafruit_FONA::begin(Stream &port) { + mySerial = &port; + + pinMode(_rstpin, OUTPUT); + digitalWrite(_rstpin, HIGH); + delay(10); + digitalWrite(_rstpin, LOW); + delay(100); + digitalWrite(_rstpin, HIGH); + + // give 7 seconds to reboot + delay(7000); + + while (mySerial->available()) mySerial->read(); + + sendCheckReply(F("AT"), F("OK")); + delay(100); + sendCheckReply(F("AT"), F("OK")); + delay(100); + sendCheckReply(F("AT"), F("OK")); + delay(100); + + // turn off Echo! + sendCheckReply(F("ATE0"), F("OK")); + delay(100); + + if (! sendCheckReply(F("ATE0"), F("OK"))) { + return false; + } + + // turn on hangupitude + sendCheckReply(F("AT+CVHU=0"), F("OK")); + + delay(100); + flushInput(); + +#ifdef ADAFRUIT_FONA_DEBUG + Serial.print("\t---> "); Serial.println("ATI"); +#endif + + mySerial->println("ATI"); + + readline(500, true); + +#ifdef ADAFRUIT_FONA_DEBUG + Serial.print (F("\t<--- ")); Serial.println(replybuffer); +#endif + + if (strstr_P(replybuffer, (prog_char *)F("SIM808 R14")) != 0) { + _type = FONA808_V2; + } else if (strstr_P(replybuffer, (prog_char *)F("SIM808 R13")) != 0) { + _type = FONA808_V1; + } else if (strstr_P(replybuffer, (prog_char *)F("SIM800 R13")) != 0) { + _type = FONA800L; + } else if (strstr_P(replybuffer, (prog_char *)F("SIMCOM_SIM5320A")) != 0) { + _type = FONA3G_A; + } else if (strstr_P(replybuffer, (prog_char *)F("SIMCOM_SIM5320E")) != 0) { + _type = FONA3G_E; + } + + return true; +} + + +/********* Serial port ********************************************/ +boolean Adafruit_FONA::setBaudrate(uint16_t baud) { + return sendCheckReply(F("AT+IPREX="), baud, F("OK")); +} + +/********* Real Time Clock ********************************************/ + +boolean Adafruit_FONA::readRTC(uint8_t *year, uint8_t *month, uint8_t *date, uint8_t *hr, uint8_t *min, uint8_t *sec) { + uint16_t v; + uint8_t mm = 0; + uint8_t dd = 0; + uint8_t hh = 0; + uint8_t nn = 0; + uint8_t ss = 0; + + *month = mm; + *date = dd; + *hr = hh; + *min = nn; + *sec = ss; + + boolean b = sendParseReply(F("AT+CCLK?"), F("+CCLK: "), &v, '/', 0); + *year = v; + Serial.println(*year); + return b; +} + +boolean Adafruit_FONA::enableRTC(uint8_t i) { + if (! sendCheckReply(F("AT+CLTS="), i, F("OK"))) + return false; + return sendCheckReply(F("AT&W"), F("OK")); +} + + +/********* BATTERY & ADC ********************************************/ + +/* returns value in mV (uint16_t) */ +boolean Adafruit_FONA::getBattVoltage(uint16_t *v) { + return sendParseReply(F("AT+CBC"), F("+CBC: "), v, ',', 2); +} + +/* returns value in mV (uint16_t) */ +boolean Adafruit_FONA_3G::getBattVoltage(uint16_t *v) { + float f; + boolean b = sendParseReply(F("AT+CBC"), F("+CBC: "), &f, ',', 2); + *v = f*1000; + return b; +} + + +/* returns the percentage charge of battery as reported by sim800 */ +boolean Adafruit_FONA::getBattPercent(uint16_t *p) { + return sendParseReply(F("AT+CBC"), F("+CBC: "), p, ',', 1); +} + +boolean Adafruit_FONA::getADCVoltage(uint16_t *v) { + return sendParseReply(F("AT+CADC?"), F("+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] = 0; + char sendOK[3] = "OK"; + +// return sendCheckReply(sendbuff, "OK"); + return sendCheckReply(sendbuff, sendOK); +} + +uint8_t Adafruit_FONA::getSIMCCID(char *ccid) +{ + + getReply(F("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(F("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(F("AT+CREG?"), F("+CREG: "), &status, ',', 1)) return 0; + + return status; +} + + +uint8_t Adafruit_FONA::getRSSI(void) { + uint16_t reply; + + if (! sendParseReply(F("AT+CSQ"), F("+CSQ: "), &reply) ) return 0; + + return reply; +} + +/********* AUDIO *******************************************************/ + +boolean Adafruit_FONA::setAudio(uint8_t a) { + // 0 is headset, 1 is external audio + if (a > 1) return false; + + return sendCheckReply(F("AT+CHFA="), a, F("OK")); +} + +uint8_t Adafruit_FONA::getVolume(void) { + uint16_t reply; + + if (! sendParseReply(F("AT+CLVL?"), F("+CLVL: "), &reply) ) return 0; + + return reply; +} + +boolean Adafruit_FONA::setVolume(uint8_t i) { + return sendCheckReply(F("AT+CLVL="), i, F("OK")); +} + + +boolean Adafruit_FONA::playDTMF(char dtmf) { + char str[4]; + str[0] = '\"'; + str[1] = dtmf; + str[2] = '\"'; + str[3] = 0; + return sendCheckReply(F("AT+CLDTMF=3,"), str, F("OK")); +} + +boolean Adafruit_FONA::playToolkitTone(uint8_t t, uint16_t len) { + return sendCheckReply(F("AT+STTONE=1,"), t, len, F("OK")); +} + +boolean Adafruit_FONA_3G::playToolkitTone(uint8_t t, uint16_t len) { + if (! sendCheckReply(F("AT+CPTONE="), t, F("OK"))) + return false; + delay(len); + return sendCheckReply(F("AT+CPTONE=0"), F("OK")); +} + +boolean Adafruit_FONA::setMicVolume(uint8_t a, uint8_t level) { + // 0 is headset, 1 is external audio + if (a > 1) return false; + + return sendCheckReply(F("AT+CMIC="), a, level, F("OK")); +} + +/********* FM RADIO *******************************************************/ + + +boolean Adafruit_FONA::FMradio(boolean onoff, uint8_t a) { + if (! onoff) { + return sendCheckReply(F("AT+FMCLOSE"), F("OK")); + } + + // 0 is headset, 1 is external audio + if (a > 1) return false; + + return sendCheckReply(F("AT+FMOPEN="), a, F("OK")); +} + +boolean Adafruit_FONA::tuneFMradio(uint16_t station) { + // Fail if FM station is outside allowed range. + if ((station < 870) || (station > 1090)) + return false; + + return sendCheckReply(F("AT+FMFREQ="), station, F("OK")); +} + +boolean 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(F("AT+FMVOLUME="), i, F("OK")); +} + +int8_t Adafruit_FONA::getFMVolume() { + uint16_t level; + + if (! sendParseReply(F("AT+FMVOLUME?"), F("+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(F("AT+FMSIGNAL="), station, FONA_DEFAULT_TIMEOUT_MS); + // Check response starts with expected value. + char *p = strstr_P(replybuffer, PSTR("+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 **************************************************/ + +boolean Adafruit_FONA::setPWM(uint16_t period, uint8_t duty) { + if (period > 2000) return false; + if (duty > 100) return false; + + return sendCheckReply(F("AT+SPWM=0,"), period, duty, F("OK")); +} + +/********* CALL PHONES **************************************************/ +boolean Adafruit_FONA::callPhone(char *number) { + char sendbuff[35] = "ATD"; + strncpy(sendbuff+3, number, min(30, strlen(number))); + uint8_t x = strlen(sendbuff); + sendbuff[x] = ';'; + sendbuff[x+1] = 0; + //Serial.println(sendbuff); + char sendOK[3] = "OK"; + +// return sendCheckReply(sendbuff, "OK"); + return sendCheckReply(sendbuff, sendOK); + +} + +boolean Adafruit_FONA::hangUp(void) { + return sendCheckReply(F("ATH0"), F("OK")); +} + +boolean Adafruit_FONA_3G::hangUp(void) { + getReply(F("ATH")); + + return (strstr_P(replybuffer, (prog_char *)F("VOICE CALL: END")) != 0); +} + +boolean Adafruit_FONA::pickUp(void) { + return sendCheckReply(F("ATA"), F("OK")); +} + +boolean Adafruit_FONA_3G::pickUp(void) { + return sendCheckReply(F("ATA"), F("VOICE CALL: BEGIN")); +} + + +void Adafruit_FONA::onIncomingCall() { + #ifdef ADAFRUIT_FONA_DEBUG + Serial.print(F("> ")); Serial.println(F("Incoming call...")); + #endif + Adafruit_FONA::_incomingCall = true; +} + +boolean Adafruit_FONA::_incomingCall = false; + +boolean Adafruit_FONA::callerIdNotification(boolean enable, uint8_t interrupt) { + if(enable){ + attachInterrupt(interrupt, onIncomingCall, FALLING); + return sendCheckReply(F("AT+CLIP=1"), F("OK")); + } + + detachInterrupt(interrupt); + return sendCheckReply(F("AT+CLIP=0"), F("OK")); +} + +boolean Adafruit_FONA::incomingCallNumber(char* phonenum) { + //+CLIP: "",145,"",0,"",0 + if(!Adafruit_FONA::_incomingCall) + return false; + + readline(); + while(!strcmp_P(replybuffer, (prog_char*)F("RING")) == 0) { + flushInput(); + readline(); + } + + readline(); //reads incoming phone number line + + parseReply(F("+CLIP: \""), phonenum, '"'); + + #ifdef ADAFRUIT_FONA_DEBUG + Serial.print(F("Phone Number: ")); + Serial.println(replybuffer); + #endif + + Adafruit_FONA::_incomingCall = false; + return true; +} + +/********* SMS **********************************************************/ + +uint8_t Adafruit_FONA::getSMSInterrupt(void) { + uint16_t reply; + + if (! sendParseReply(F("AT+CFGRI?"), F("+CFGRI: "), &reply) ) return 0; + + return reply; +} + +boolean Adafruit_FONA::setSMSInterrupt(uint8_t i) { + return sendCheckReply(F("AT+CFGRI="), i, F("OK")); +} + +int8_t Adafruit_FONA::getNumSMS(void) { + uint16_t numsms; + + // get into text mode + if (! sendCheckReply(F("AT+CMGF=1"), F("OK"))) return -1; + + // ask how many sms are stored + if ( (_type == FONA3G_A) || (_type == FONA3G_E) ) { + if (! sendParseReply(F("AT+CPMS?"), F("+CPMS: \"ME\","), &numsms) ) return -1; + } else { + if (! sendParseReply(F("AT+CPMS?"), F("+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! +boolean Adafruit_FONA::readSMS(uint8_t i, char *smsbuff, + uint16_t maxlen, uint16_t *readlen) { + // text mode + if (! sendCheckReply(F("AT+CMGF=1"), F("OK"))) return false; + + // show all text mode parameters + if (! sendCheckReply(F("AT+CSDH=1"), F("OK"))) return false; + + // parse out the SMS len + uint16_t thesmslen = 0; + + //getReply(F("AT+CMGR="), i, 1000); // do not print debug! + mySerial->print(F("AT+CMGR=")); + mySerial->println(i); + readline(1000); // timeout + + //Serial.print(F("Reply: ")); Serial.println(replybuffer); + // parse it out... + if (! parseReply(F("+CMGR:"), &thesmslen, ',', 11)) { + *readlen = 0; + return false; + } + + readRaw(thesmslen); + + flushInput(); + + uint16_t thelen = min(maxlen, strlen(replybuffer)); + strncpy(smsbuff, replybuffer, thelen); + smsbuff[thelen] = 0; // end the string + +#ifdef ADAFRUIT_FONA_DEBUG + Serial.println(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. +boolean Adafruit_FONA::getSMSSender(uint8_t i, char *sender, int senderlen) { + // Ensure text mode and all text mode parameters are sent. + if (! sendCheckReply(F("AT+CMGF=1"), F("OK"))) return false; + if (! sendCheckReply(F("AT+CSDH=1"), F("OK"))) return false; + // Send command to retrieve SMS message and parse a line of response. + mySerial->print(F("AT+CMGR=")); + mySerial->println(i); + readline(1000); + // Parse the second field in the response. + boolean result = parseReplyQuoted(F("+CMGR:"), sender, senderlen, ',', 1); + // Drop any remaining data from the response. + flushInput(); + return result; +} + +boolean Adafruit_FONA::sendSMS(char *smsaddr, char *smsmsg) +{ +// char sendOK[3] = "OK"; +// if (!sendCheckReply("AT+CMGF=1", "OK")) return -1; + if (!sendCheckReply(F("AT+CMGF=1"), F("OK"))) return -1; + + char sendcmd[30] = "AT+CMGS=\""; + char sendgreater[3] = "> "; + strncpy(sendcmd+9, smsaddr, 30-9-2); // 9 bytes beginning, 2 bytes for close quote + null + sendcmd[strlen(sendcmd)] = '\"'; + +// if (!sendCheckReply(sendcmd, "> ")) return false; + if (!sendCheckReply(sendcmd, sendgreater)) return false; +#ifdef ADAFRUIT_FONA_DEBUG + Serial.print(F("> ")); Serial.println(smsmsg); +#endif + mySerial->println(smsmsg); + mySerial->println(); + mySerial->write(0x1A); +#ifdef ADAFRUIT_FONA_DEBUG + Serial.println("^Z"); +#endif + if ( (_type == FONA3G_A) || (_type == FONA3G_E) ) { + // Eat two sets of CRLF + readline(200); + //Serial.print("Line 1: "); Serial.println(strlen(replybuffer)); + readline(200); + //Serial.print("Line 2: "); Serial.println(strlen(replybuffer)); + } + readline(10000); // read the +CMGS reply, wait up to 10 seconds!!! + //Serial.print("Line 3: "); Serial.println(strlen(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; +} + + +boolean Adafruit_FONA::deleteSMS(uint8_t i) +{ +// if (!sendCheckReply("AT+CMGF=1", "OK")) return -1; + if (!sendCheckReply(F("AT+CMGF=1"), F("OK"))) return -1; + // read an sms + char sendbuff[12] = "AT+CMGD=000"; + char sendOK[3] = "OK"; + sendbuff[8] = (i / 100) + '0'; + i %= 100; + sendbuff[9] = (i / 10) + '0'; + i %= 10; + sendbuff[10] = i + '0'; + +// return sendCheckReply(sendbuff, "OK", 2000); + return sendCheckReply(sendbuff, sendOK, 2000); +} + +/********* TIME **********************************************************/ + +boolean Adafruit_FONA::enableNetworkTimeSync(boolean onoff) { + if (onoff) { + if (! sendCheckReply(F("AT+CLTS=1"), F("OK"))) + return false; + } else { + if (! sendCheckReply(F("AT+CLTS=0"), F("OK"))) + return false; + } + + flushInput(); // eat any 'Unsolicted Result Code' + + return true; +} + +boolean Adafruit_FONA::enableNTPTimeSync(boolean onoff, const __FlashStringHelper *ntpserver) { + if (onoff) { + if (! sendCheckReply(F("AT+CNTPCID=1"), F("OK"))) + return false; + + mySerial->print(F("AT+CNTP=\"")); + if (ntpserver != 0) { + mySerial->print(ntpserver); + } else { + mySerial->print(F("pool.ntp.org")); + } + mySerial->println(F("\",0")); + readline(FONA_DEFAULT_TIMEOUT_MS); + if (strcmp(replybuffer, "OK") != 0) + return false; + + if (! sendCheckReply(F("AT+CNTP"), F("OK"), 10000)) + return false; + + uint16_t status; + readline(10000); + if (! parseReply(F("+CNTP:"), &status)) + return false; + } else { + if (! sendCheckReply(F("AT+CNTPCID=0"), F("OK"))) + return false; + } + + return true; +} + +boolean Adafruit_FONA::getTime(char *buff, uint16_t maxlen) { + getReply(F("AT+CCLK?"), (uint16_t) 10000); + if (strncmp(replybuffer, "+CCLK: ", 7) != 0) + return false; + + char *p = replybuffer+7; + uint16_t lentocopy = min(maxlen-1, strlen(p)); + strncpy(buff, p, lentocopy+1); + buff[lentocopy] = 0; + + readline(); // eat OK + + return true; +} + +/********* GPS **********************************************************/ + + +boolean Adafruit_FONA::enableGPS(boolean onoff) { + uint16_t state; + + // first check if its already on or off + + if (_type == FONA808_V2) { + if (! sendParseReply(F("AT+CGNSPWR?"), F("+CGNSPWR: "), &state) ) + return false; + } else { + if (! sendParseReply(F("AT+CGPSPWR?"), F("+CGPSPWR: "), &state)) + return false; + } + + if (onoff && !state) { + if (_type == FONA808_V2) { + if (! sendCheckReply(F("AT+CGNSPWR=1"), F("OK"))) // try GNS command + return false; + } else { + if (! sendCheckReply(F("AT+CGPSPWR=1"), F("OK"))) + return false; + } + } else if (!onoff && state) { + if (_type == FONA808_V2) { + if (! sendCheckReply(F("AT+CGNSPWR=0"), F("OK"))) // try GNS command + return false; + } else { + if (! sendCheckReply(F("AT+CGPSPWR=0"), F("OK"))) + return false; + } + } + return true; +} + + + +boolean Adafruit_FONA_3G::enableGPS(boolean onoff) { + uint16_t state; + + // first check if its already on or off + if (! Adafruit_FONA::sendParseReply(F("AT+CGPS?"), F("+CGPS: "), &state) ) + return false; + + if (onoff && !state) { + if (! sendCheckReply(F("AT+CGPS=1"), F("OK"))) + return false; + } else if (!onoff && state) { + if (! sendCheckReply(F("AT+CGPS=0"), F("OK"))) + return false; + // this takes a little time + readline(2000); // eat '+CGPS: 0' + } + return true; +} + +int8_t Adafruit_FONA::GPSstatus(void) { + if (_type == FONA808_V2) { + // 808 V2 uses GNS commands and doesn't have an explicit 2D/3D fix status. + // Instead just look for a fix and if found assume it's a 3D fix. + getReply(F("AT+CGNSINF")); + char *p = strstr_P(replybuffer, (prog_char*)F("+CGNSINF: ")); + if (p == 0) return -1; + p+=12; // Skip to second value, fix status. + readline(); // eat 'OK' + //Serial.println(p); + // Assume if the fix status is '1' then we have a 3D fix, otherwise no fix. + if (p[0] == '1') return 3; + else return 0; + } + if (_type == FONA3G_A || _type == FONA3G_E) { + // FONA 3G doesn't have an explicit 2D/3D fix status. + // Instead just look for a fix and if found assume it's a 3D fix. + getReply(F("AT+CGPSINFO")); + char *p = strstr_P(replybuffer, (prog_char*)F("+CGPSINFO:")); + if (p == 0) return -1; + if (p[10] != ',') return 3; // if you get anything, its 3D fix + return 0; + } + else { + // 808 V1 looks for specific 2D or 3D fix state. + getReply(F("AT+CGPSSTATUS?")); + char *p = strstr_P(replybuffer, (prog_char*)F("SSTATUS: Location ")); + if (p == 0) return -1; + p+=18; + readline(); // eat 'OK' + //Serial.println(p); + 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; + + if ( (_type == FONA3G_A) || (_type == FONA3G_E) ) { + getReply(F("AT+CGPSINFO")); + } else if (_type == FONA808_V1) { + getReply(F("AT+CGPSINF="), x); + } else { + getReply(F("AT+CGNSINF")); + } + + char *p = strstr_P(replybuffer, (prog_char*)F("SINF")); + if (p == 0) { + buffer[0] = 0; + return 0; + } + + p+=6; + + uint8_t len = max((unsigned)maxbuff-1, (unsigned) strlen(p)); + strncpy(buffer, p, len); + buffer[len] = 0; + + readline(); // eat 'OK' + return len; +} + +boolean 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; + + if (_type == FONA3G_A || _type == FONA3G_E) +{ + // Parse 3G respose + // +CGPSINFO:4043.000000,N,07400.000000,W,151015,203802.1,-12.0,0.0,0 + // skip beginning + char *tok = {0}; + strcpy(tok, ""); + + + // grab the latitude + char *latp = strtok(gpsbuffer, ","); + 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; + + // skip date & time + tok = strtok(NULL, ","); + tok = strtok(NULL, ","); + + // only grab altitude if needed + if (altitude != NULL) { + // grab altitude + char *altp = strtok(NULL, ","); + if (! altp) return false; + *altitude = atof(altp); + } + + // only grab speed if needed + if (speed_kph != NULL) { + // grab the speed in km/h + char *speedp = strtok(NULL, ","); + if (! speedp) return false; + + *speed_kph = atof(speedp); + } + + // only grab heading if needed + if (heading != NULL) { + + // grab the speed in knots + char *coursep = strtok(NULL, ","); + if (! coursep) return false; + + *heading = atof(coursep); + } + + 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; + + } else if (_type == FONA808_V2) + { + // Parse 808 V2 response. See table 2-3 from here for format: + // http://www.adafruit.com/datasheets/SIM800%20Series_GNSS_Application%20Note%20V1.00.pdf + + // skip GPS run status + char *tok = strtok(gpsbuffer, ","); + if (! tok) return false; + + // skip fix status + tok = strtok(NULL, ","); + if (! tok) return false; + + // skip date + tok = strtok(NULL, ","); + if (! tok) return false; + + // grab the latitude + char *latp = strtok(NULL, ","); + if (! latp) return false; + + // grab longitude + char *longp = strtok(NULL, ","); + if (! longp) return false; + + *lat = atof(latp); + *lon = atof(longp); + + // only grab altitude if needed + if (altitude != NULL) { + // grab altitude + char *altp = strtok(NULL, ","); + if (! altp) return false; + + *altitude = atof(altp); + } + + // only grab speed if needed + if (speed_kph != NULL) { + // grab the speed in km/h + char *speedp = strtok(NULL, ","); + if (! speedp) return false; + + *speed_kph = atof(speedp); + } + + // only grab heading if needed + if (heading != NULL) { + + // grab the speed in knots + char *coursep = strtok(NULL, ","); + if (! coursep) return false; + + *heading = atof(coursep); + } + } + else { + // Parse 808 V1 response. + + // 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; + +} + +boolean Adafruit_FONA::enableGPSNMEA(uint8_t i) { + + char sendbuff[15] = "AT+CGPSOUT=000"; + char sendOK[3] = "OK"; + sendbuff[11] = (i / 100) + '0'; + i %= 100; + sendbuff[12] = (i / 10) + '0'; + i %= 10; + sendbuff[13] = i + '0'; + + if (_type == FONA808_V2) { + if (i) + return sendCheckReply(F("AT+CGNSTST=1"), F("OK")); + else + return sendCheckReply(F("AT+CGNSTST=0"), F("OK")); + } else { +// return sendCheckReply(sendbuff, "OK", 2000); + return sendCheckReply(sendbuff, sendOK, 2000); + } +} + + +/********* GPRS **********************************************************/ + + +boolean Adafruit_FONA::enableGPRS(boolean onoff) { + + if (onoff) { + // disconnect all sockets + sendCheckReply(F("AT+CIPSHUT"), F("SHUT OK"), 5000); + + if (! sendCheckReply(F("AT+CGATT=1"), F("OK"), 10000)) + return false; + + // set bearer profile! connection type GPRS + if (! sendCheckReply(F("AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\""), + F("OK"), 10000)) + return false; + + // set bearer profile access point name + if (apn) { + // Send command AT+SAPBR=3,1,"APN","" where is the configured APN value. + if (! sendCheckReplyQuoted(F("AT+SAPBR=3,1,\"APN\","), apn, F("OK"), 10000)) + return false; + + // set username/password + if (apnusername) { + // Send command AT+SAPBR=3,1,"USER","" where is the configured APN username. + if (! sendCheckReplyQuoted(F("AT+SAPBR=3,1,\"USER\","), apnusername, F("OK"), 10000)) + return false; + } + if (apnpassword) { + // Send command AT+SAPBR=3,1,"PWD","" where is the configured APN password. + if (! sendCheckReplyQuoted(F("AT+SAPBR=3,1,\"PWD\","), apnpassword, F("OK"), 10000)) + return false; + } + } + + // open GPRS context + if (! sendCheckReply(F("AT+SAPBR=1,1"), F("OK"), 10000)) + return false; + } else { + // disconnect all sockets + if (! sendCheckReply(F("AT+CIPSHUT"), F("SHUT OK"), 5000)) + return false; + + // close GPRS context + if (! sendCheckReply(F("AT+SAPBR=0,1"), F("OK"), 10000)) + return false; + + if (! sendCheckReply(F("AT+CGATT=0"), F("OK"), 10000)) + return false; + + } + return true; +} + +boolean Adafruit_FONA_3G::enableGPRS(boolean onoff) { + + if (onoff) { + // disconnect all sockets + //sendCheckReply(F("AT+CIPSHUT"), F("SHUT OK"), 5000); + + if (! sendCheckReply(F("AT+CGATT=1"), F("OK"), 10000)) + return false; + + + // set bearer profile access point name + if (apn) { + // Send command AT+CGSOCKCONT=1,"IP","" where is the configured APN name. + if (! sendCheckReplyQuoted(F("AT+CGSOCKCONT=1,\"IP\","), apn, F("OK"), 10000)) + return false; + + // set username/password + if (apnusername) { + char authstring[100] = "AT+CGAUTH=1,1,\""; + char *strp = authstring + strlen(authstring); + strcpy_P(strp, (prog_char *)apnusername); + strp+=strlen_P((prog_char *)apnusername); + strp[0] = '\"'; + strp++; + strp[0] = 0; + + if (apnpassword) { + strp[0] = ','; strp++; + strp[0] = '\"'; strp++; + strcpy_P(strp, (prog_char *)apnpassword); + strp+=strlen_P((prog_char *)apnpassword); + strp[0] = '\"'; + strp++; + strp[0] = 0; + } + + char sendOK[3] = "OK"; +// if (!sendCheckReply(authstring, "OK", 10000)) + if (!sendCheckReply(authstring, sendOK, 10000)) + return false; + } + } + + // connect in transparent + if (! sendCheckReply(F("AT+CIPMODE=1"), F("OK"), 10000)) + return false; + // open network (?) + if (! sendCheckReply(F("AT+NETOPEN=,,1"), F("Network opened"), 10000)) + return false; + + readline(); // eat 'OK' + } else { + // close GPRS context + if (! sendCheckReply(F("AT+NETCLOSE"), F("Network closed"), 10000)) + return false; + + readline(); // eat 'OK' + } + + return true; +} + +uint8_t Adafruit_FONA::GPRSstate(void) { + uint16_t state; + + if (! sendParseReply(F("AT+CGATT?"), F("+CGATT: "), &state) ) + return -1; + + return state; +} + +void Adafruit_FONA::setGPRSNetworkSettings(const __FlashStringHelper *apn, + const __FlashStringHelper *username, const __FlashStringHelper *password) { + this->apn = apn; + this->apnusername = username; + this->apnpassword = password; +} + +boolean Adafruit_FONA::getGSMLoc(uint16_t *errorcode, char *buff, uint16_t maxlen) { + + getReply(F("AT+CIPGSMLOC=1,1"), (uint16_t)10000); + + if (! parseReply(F("+CIPGSMLOC: "), errorcode)) + return false; + + char *p = replybuffer+14; + uint16_t lentocopy = min(maxlen-1, strlen(p)); + strncpy(buff, p, lentocopy+1); + + readline(); // eat OK + + return true; +} + +boolean 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; + + // +CIPGSMLOC: 0,-74.007729,40.730160,2015/10/15,19:24:55 + // tokenize the gps buffer to locate the lat & long + char *longp = strtok(gpsbuffer, ","); + if (! longp) return false; + + char *latp = strtok(NULL, ","); + if (! latp) return false; + + *lat = atof(latp); + *lon = atof(longp); + + return true; + +} +/********* TCP FUNCTIONS ************************************/ + + +boolean Adafruit_FONA::TCPconnect(char *server, uint16_t port) { + flushInput(); + + // close all old connections + if (! sendCheckReply(F("AT+CIPSHUT"), F("SHUT OK"), 5000) ) return false; + + // single connection at a time + if (! sendCheckReply(F("AT+CIPMUX=0"), F("OK")) ) return false; + + // manually read data + if (! sendCheckReply(F("AT+CIPRXGET=1"), F("OK")) ) return false; + +#ifdef ADAFRUIT_FONA_DEBUG + Serial.print(F("AT+CIPSTART=\"TCP\",\"")); + Serial.print(server); + Serial.print(F("\",\"")); + Serial.print(port); + Serial.println(F("\"")); +#endif + + mySerial->print(F("AT+CIPSTART=\"TCP\",\"")); + mySerial->print(server); + mySerial->print(F("\",\"")); + mySerial->print(port); + mySerial->println(F("\"")); + + if (! expectReply(F("OK"))) return false; + return (expectReply(F("CONNECT OK"))); + +} + +boolean Adafruit_FONA::TCPclose(void) { + return sendCheckReply(F("AT+CIPCLOSE"), F("OK")); +} + +boolean Adafruit_FONA::TCPconnected(void) { + if (! sendCheckReply(F("AT+CIPSTATUS"), F("OK"), 100) ) return false; + readline(100); +#ifdef ADAFRUIT_FONA_DEBUG + Serial.print (F("\t<--- ")); Serial.println(replybuffer); +#endif + return (strcmp(replybuffer, "STATE: CONNECT OK") == 0); +} + +boolean Adafruit_FONA::TCPsend(char *packet, uint8_t len) { + +#ifdef ADAFRUIT_FONA_DEBUG + Serial.print(F("AT+CIPSEND=")); + Serial.println(len); + + for (uint16_t i=0; iprint(F("AT+CIPSEND=")); + mySerial->println(len); + readline(); +#ifdef ADAFRUIT_FONA_DEBUG + Serial.print (F("\t<--- ")); Serial.println(replybuffer); +#endif + if (replybuffer[0] != '>') return false; + + mySerial->write(packet, len); + readline(3000); // wait up to 3 seconds to send the data +#ifdef ADAFRUIT_FONA_DEBUG + Serial.print (F("\t<--- ")); Serial.println(replybuffer); +#endif + + return (strcmp(replybuffer, "SEND OK") == 0); +} + +uint16_t Adafruit_FONA::TCPavailable(void) { + uint16_t avail; + + if (! sendParseReply(F("AT+CIPRXGET=4"), F("+CIPRXGET: 4,"), &avail, ',', 0) ) return false; + +#ifdef ADAFRUIT_FONA_DEBUG + Serial.print (avail); Serial.println(F(" bytes available")); +#endif + + return avail; +} + + +uint16_t Adafruit_FONA::TCPread(uint8_t *buff, uint8_t len) { + uint16_t avail; + + mySerial->print(F("AT+CIPRXGET=2,")); + mySerial->println(len); + readline(); + if (! parseReply(F("+CIPRXGET: 2,"), &avail, ',', 0)) return false; + + readRaw(avail); + +#ifdef ADAFRUIT_FONA_DEBUG + Serial.print (avail); Serial.println(F(" bytes read")); + for (uint8_t i=0;i "); + Serial.print(F("AT+HTTPPARA=\"")); + Serial.print(parameter); + Serial.println('"'); +#endif + + mySerial->print(F("AT+HTTPPARA=\"")); + mySerial->print(parameter); + if (quoted) + mySerial->print(F("\",\"")); + else + mySerial->print(F("\",")); +} + +boolean Adafruit_FONA::HTTP_para_end(boolean quoted) { + if (quoted) + mySerial->println('"'); + else + mySerial->println(); + + return expectReply(F("OK")); +} + +boolean Adafruit_FONA::HTTP_para(const __FlashStringHelper *parameter, + const char *value) { + HTTP_para_start(parameter, true); + mySerial->print(value); + return HTTP_para_end(true); +} + +boolean Adafruit_FONA::HTTP_para(const __FlashStringHelper *parameter, + const __FlashStringHelper *value) { + HTTP_para_start(parameter, true); + mySerial->print(value); + return HTTP_para_end(true); +} + +boolean Adafruit_FONA::HTTP_para(const __FlashStringHelper *parameter, + int32_t value) { + HTTP_para_start(parameter, false); + mySerial->print(value); + return HTTP_para_end(false); +} + +boolean Adafruit_FONA::HTTP_data(uint32_t size, uint32_t maxTime) { + flushInput(); + +#ifdef ADAFRUIT_FONA_DEBUG + Serial.print("\t---> "); + Serial.print(F("AT+HTTPDATA=")); + Serial.print(size); + Serial.print(","); + Serial.println(maxTime); +#endif + + mySerial->print(F("AT+HTTPDATA=")); + mySerial->print(size); + mySerial->print(","); + mySerial->println(maxTime); + + return expectReply(F("DOWNLOAD")); +} + +boolean Adafruit_FONA::HTTP_action(uint8_t method, uint16_t *status, + uint16_t *datalen, int32_t timeout) { + // Send request. + if (! sendCheckReply(F("AT+HTTPACTION="), method, F("OK"))) + return false; + + // Parse response status and size. + readline(timeout); + if (! parseReply(F("+HTTPACTION:"), status, ',', 1)) + return false; + if (! parseReply(F("+HTTPACTION:"), datalen, ',', 2)) + return false; + + return true; +} + +boolean Adafruit_FONA::HTTP_readall(uint16_t *datalen) { + getReply(F("AT+HTTPREAD")); + if (! parseReply(F("+HTTPREAD:"), datalen, ',', 0)) + return false; + + return true; +} + +boolean Adafruit_FONA::HTTP_ssl(boolean onoff) { + return sendCheckReply(F("AT+HTTPSSL="), onoff ? 1 : 0, F("OK")); +} + +/********* HTTP HIGH LEVEL FUNCTIONS ***************************/ + +boolean 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; + + Serial.print("Status: "); Serial.println(*status); + Serial.print("Len: "); Serial.println(*datalen); + + // HTTP response data + if (! HTTP_readall(datalen)) + return false; + + return true; +} + +/* +boolean Adafruit_FONA_3G::HTTP_GET_start(char *ipaddr, char *path, uint16_t port + uint16_t *status, uint16_t *datalen){ + char send[100] = "AT+CHTTPACT=\""; + char *sendp = send + strlen(send); + memset(sendp, 0, 100 - strlen(send)); + + strcpy(sendp, ipaddr); + sendp+=strlen(ipaddr); + sendp[0] = '\"'; + sendp++; + sendp[0] = ','; + itoa(sendp, port); + getReply(send, 500); + + return; + + if (! HTTP_setup(url)) + + return false; + + // HTTP GET + if (! HTTP_action(FONA_HTTP_GET, status, datalen)) + return false; + + Serial.print("Status: "); Serial.println(*status); + Serial.print("Len: "); Serial.println(*datalen); + + // HTTP response data + if (! HTTP_readall(datalen)) + return false; + + return true; +} +*/ + +void Adafruit_FONA::HTTP_GET_end(void) { + HTTP_term(); +} + +boolean Adafruit_FONA::HTTP_POST_start(char *url, + const __FlashStringHelper *contenttype, + const uint8_t *postdata, uint16_t postdatalen, + uint16_t *status, uint16_t *datalen){ + if (! HTTP_setup(url)) + return false; + + if (! HTTP_para(F("CONTENT"), contenttype)) { + return false; + } + + // HTTP POST data + if (! HTTP_data(postdatalen, 10000)) + return false; + mySerial->write(postdata, postdatalen); + if (! expectReply(F("OK"))) + return false; + + // HTTP POST + if (! HTTP_action(FONA_HTTP_POST, status, datalen)) + return false; + + Serial.print("Status: "); Serial.println(*status); + Serial.print("Len: "); Serial.println(*datalen); + + // 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 __FlashStringHelper *useragent) { + this->useragent = useragent; +} + +void Adafruit_FONA::setHTTPSRedirect(boolean onoff) { + httpsredirect = onoff; +} + +/********* HTTP HELPERS ****************************************/ + +boolean Adafruit_FONA::HTTP_setup(char *url) { + // Handle any pending + HTTP_term(); + + // Initialize and set parameters + if (! HTTP_init()) + return false; + if (! HTTP_para(F("CID"), 1)) + return false; + if (! HTTP_para(F("UA"), useragent)) + return false; + if (! HTTP_para(F("URL"), url)) + return false; + + // HTTPS redirect + if (httpsredirect) { + if (! HTTP_para(F("REDIR"),1)) + return false; + + if (! HTTP_ssl(true)) + return false; + } + + return true; +} + +/********* HELPERS *********************************************/ + +boolean Adafruit_FONA::expectReply(const __FlashStringHelper *reply, + uint16_t timeout) { + readline(timeout); +#ifdef ADAFRUIT_FONA_DEBUG + Serial.print(F("\t<--- ")); Serial.println(replybuffer); +#endif + return (strcmp_P(replybuffer, (prog_char*)reply) == 0); +} + +/********* LOW LEVEL *******************************************/ + +inline int Adafruit_FONA::available(void) { + return mySerial->available(); +} + +inline size_t Adafruit_FONA::write(uint8_t x) { + return mySerial->write(x); +} + +inline int Adafruit_FONA::read(void) { + return mySerial->read(); +} + +inline int Adafruit_FONA::peek(void) { + return mySerial->peek(); +} + +inline void Adafruit_FONA::flush() { + mySerial->flush(); +} + +void Adafruit_FONA::flushInput() { + // Read all available serial input to flush pending data. + uint16_t timeoutloop = 0; + while (timeoutloop++ < 40) { + while(available()) { + read(); + timeoutloop = 0; // If char was received reset the timer + } + delay(1); + } +} + +uint16_t Adafruit_FONA::readRaw(uint16_t b) { + uint16_t idx = 0; + + while (b && (idx < sizeof(replybuffer)-1)) { + if (mySerial->available()) { + replybuffer[idx] = mySerial->read(); + idx++; + b--; + } + } + replybuffer[idx] = 0; + + return idx; +} + +uint8_t Adafruit_FONA::readline(uint16_t timeout, boolean multiline) { + uint16_t replyidx = 0; + + while (timeout--) { + if (replyidx >= 254) { + //Serial.println(F("SPACE")); + break; + } + + while(mySerial->available()) { + char c = mySerial->read(); + 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; + //Serial.print(c, HEX); Serial.print("#"); Serial.println(c); + replyidx++; + } + + if (timeout == 0) { + //Serial.println(F("TIMEOUT")); + break; + } + delay(1); + } + replybuffer[replyidx] = 0; // null term + return replyidx; +} + +uint8_t Adafruit_FONA::getReply(char *send, uint16_t timeout) { + flushInput(); + +#ifdef ADAFRUIT_FONA_DEBUG + Serial.print("\t---> "); Serial.println(send); +#endif + + mySerial->println(send); + + uint8_t l = readline(timeout); +#ifdef ADAFRUIT_FONA_DEBUG + Serial.print (F("\t<--- ")); Serial.println(replybuffer); +#endif + return l; +} + +uint8_t Adafruit_FONA::getReply(const __FlashStringHelper *send, uint16_t timeout) { + flushInput(); + +#ifdef ADAFRUIT_FONA_DEBUG + Serial.print("\t---> "); Serial.println(send); +#endif + + mySerial->println(send); + + uint8_t l = readline(timeout); +#ifdef ADAFRUIT_FONA_DEBUG + Serial.print (F("\t<--- ")); Serial.println(replybuffer); +#endif + return l; +} + +// Send prefix, suffix, and newline. Return response (and also set replybuffer with response). +uint8_t Adafruit_FONA::getReply(const __FlashStringHelper *prefix, char *suffix, uint16_t timeout) { + flushInput(); + +#ifdef ADAFRUIT_FONA_DEBUG + Serial.print("\t---> "); Serial.print(prefix); Serial.println(suffix); +#endif + + mySerial->print(prefix); + mySerial->println(suffix); + + uint8_t l = readline(timeout); +#ifdef ADAFRUIT_FONA_DEBUG + Serial.print (F("\t<--- ")); Serial.println(replybuffer); +#endif + return l; +} + +// Send prefix, suffix, and newline. Return response (and also set replybuffer with response). +uint8_t Adafruit_FONA::getReply(const __FlashStringHelper *prefix, int32_t suffix, uint16_t timeout) { + flushInput(); + +#ifdef ADAFRUIT_FONA_DEBUG + Serial.print("\t---> "); Serial.print(prefix); Serial.println(suffix, DEC); +#endif + + mySerial->print(prefix); + mySerial->println(suffix, DEC); + + uint8_t l = readline(timeout); +#ifdef ADAFRUIT_FONA_DEBUG + Serial.print (F("\t<--- ")); Serial.println(replybuffer); +#endif + return l; +} + +// Send prefix, suffix, suffix2, and newline. Return response (and also set replybuffer with response). +uint8_t Adafruit_FONA::getReply(const __FlashStringHelper *prefix, int32_t suffix1, int32_t suffix2, uint16_t timeout) { + flushInput(); + +#ifdef ADAFRUIT_FONA_DEBUG + Serial.print("\t---> "); Serial.print(prefix); + Serial.print(suffix1, DEC); Serial.print(","); Serial.println(suffix2, DEC); +#endif + + mySerial->print(prefix); + mySerial->print(suffix1); + mySerial->print(','); + mySerial->println(suffix2, DEC); + + uint8_t l = readline(timeout); +#ifdef ADAFRUIT_FONA_DEBUG + Serial.print (F("\t<--- ")); Serial.println(replybuffer); +#endif + return l; +} + +// Send prefix, ", suffix, ", and newline. Return response (and also set replybuffer with response). +uint8_t Adafruit_FONA::getReplyQuoted(const __FlashStringHelper *prefix, const __FlashStringHelper *suffix, uint16_t timeout) { + flushInput(); + +#ifdef ADAFRUIT_FONA_DEBUG + Serial.print("\t---> "); Serial.print(prefix); + Serial.print('"'); Serial.print(suffix); Serial.println('"'); +#endif + + mySerial->print(prefix); + mySerial->print('"'); + mySerial->print(suffix); + mySerial->println('"'); + + uint8_t l = readline(timeout); +#ifdef ADAFRUIT_FONA_DEBUG + Serial.print (F("\t<--- ")); Serial.println(replybuffer); +#endif + return l; +} + +boolean Adafruit_FONA::sendCheckReply(char *send, char *reply, uint16_t timeout) { + getReply(send, timeout); + +/* + for (uint8_t i=0; i 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 + ****************************************************/ +#ifndef ADAFRUIT_FONA_H +#define ADAFRUIT_FONA_H + +#if (ARDUINO >= 100) + #include "Arduino.h" + #ifndef __SAM3X8E__ // Arduino Due doesn't support SoftwareSerial + #include + #endif +#else + #include "WProgram.h" + #include +#endif + +#define ADAFRUIT_FONA_DEBUG + +#define FONA800L 1 +#define FONA800H 6 + +#define FONA808_V1 2 +#define FONA808_V2 3 + +#define FONA3G_A 4 +#define FONA3G_E 5 + + +#define FONA_HEADSETAUDIO 0 +#define FONA_EXTAUDIO 1 + +#define FONA_STTONE_DIALTONE 1 +#define FONA_STTONE_BUSY 2 +#define FONA_STTONE_CONGESTION 3 +#define FONA_STTONE_PATHACK 4 +#define FONA_STTONE_DROPPED 5 +#define FONA_STTONE_ERROR 6 +#define FONA_STTONE_CALLWAIT 7 +#define FONA_STTONE_RINGING 8 +#define FONA_STTONE_BEEP 16 +#define FONA_STTONE_POSTONE 17 +#define FONA_STTONE_ERRTONE 18 +#define FONA_STTONE_INDIANDIALTONE 19 +#define FONA_STTONE_USADIALTONE 20 + +#define FONA_DEFAULT_TIMEOUT_MS 500 + +#define FONA_HTTP_GET 0 +#define FONA_HTTP_POST 1 +#define FONA_HTTP_HEAD 2 + +class Adafruit_FONA : public Stream { + public: + Adafruit_FONA(int8_t r); + boolean begin(Stream &port); + uint8_t type(); + + // Stream + int available(void); + size_t write(uint8_t x); + int read(void); + int peek(void); + void flush(); + + // FONA 3G requirements + boolean setBaudrate(uint16_t baud); + + // RTC + boolean enableRTC(uint8_t i); + boolean readRTC(uint8_t *year, uint8_t *month, uint8_t *date, uint8_t *hr, uint8_t *min, uint8_t *sec); + + // Battery and ADC + boolean getADCVoltage(uint16_t *v); + boolean getBattPercent(uint16_t *p); + boolean getBattVoltage(uint16_t *v); + + // SIM query + uint8_t unlockSIM(char *pin); + uint8_t getSIMCCID(char *ccid); + uint8_t getNetworkStatus(void); + uint8_t getRSSI(void); + + // IMEI + uint8_t getIMEI(char *imei); + + // set Audio output + boolean setAudio(uint8_t a); + boolean setVolume(uint8_t i); + uint8_t getVolume(void); + boolean playToolkitTone(uint8_t t, uint16_t len); + boolean setMicVolume(uint8_t a, uint8_t level); + boolean playDTMF(char tone); + + // FM radio functions. + boolean tuneFMradio(uint16_t station); + boolean FMradio(boolean onoff, uint8_t a = FONA_HEADSETAUDIO); + boolean setFMVolume(uint8_t i); + int8_t getFMVolume(); + int8_t getFMSignalLevel(uint16_t station); + + // SMS handling + boolean setSMSInterrupt(uint8_t i); + uint8_t getSMSInterrupt(void); + int8_t getNumSMS(void); + boolean readSMS(uint8_t i, char *smsbuff, uint16_t max, uint16_t *readsize); + boolean sendSMS(char *smsaddr, char *smsmsg); + boolean deleteSMS(uint8_t i); + boolean getSMSSender(uint8_t i, char *sender, int senderlen); + + // Time + boolean enableNetworkTimeSync(boolean onoff); + boolean enableNTPTimeSync(boolean onoff, const __FlashStringHelper *ntpserver=0); + boolean getTime(char *buff, uint16_t maxlen); + + // GPRS handling + boolean enableGPRS(boolean onoff); + uint8_t GPRSstate(void); + boolean getGSMLoc(uint16_t *replycode, char *buff, uint16_t maxlen); + boolean getGSMLoc(float *lat, float *lon); + void setGPRSNetworkSettings(const __FlashStringHelper *apn, const __FlashStringHelper *username=0, const __FlashStringHelper *password=0); + + // GPS handling + boolean enableGPS(boolean onoff); + int8_t GPSstatus(void); + uint8_t getGPS(uint8_t arg, char *buffer, uint8_t maxbuff); + boolean getGPS(float *lat, float *lon, float *speed_kph=0, float *heading=0, float *altitude=0); + boolean enableGPSNMEA(uint8_t nmea); + + // TCP raw connections + boolean TCPconnect(char *server, uint16_t port); + boolean TCPclose(void); + boolean TCPconnected(void); + boolean TCPsend(char *packet, uint8_t len); + uint16_t TCPavailable(void); + uint16_t TCPread(uint8_t *buff, uint8_t len); + + // HTTP low level interface (maps directly to SIM800 commands). + boolean HTTP_init(); + boolean HTTP_term(); + void HTTP_para_start(const __FlashStringHelper *parameter, boolean quoted = true); + boolean HTTP_para_end(boolean quoted = true); + boolean HTTP_para(const __FlashStringHelper *parameter, const char *value); + boolean HTTP_para(const __FlashStringHelper *parameter, const __FlashStringHelper *value); + boolean HTTP_para(const __FlashStringHelper *parameter, int32_t value); + boolean HTTP_data(uint32_t size, uint32_t maxTime=10000); + boolean HTTP_action(uint8_t method, uint16_t *status, uint16_t *datalen, int32_t timeout = 10000); + boolean HTTP_readall(uint16_t *datalen); + boolean HTTP_ssl(boolean onoff); + + // HTTP high level interface (easier to use, less flexible). + boolean HTTP_GET_start(char *url, uint16_t *status, uint16_t *datalen); + void HTTP_GET_end(void); + boolean HTTP_POST_start(char *url, const __FlashStringHelper *contenttype, const uint8_t *postdata, uint16_t postdatalen, uint16_t *status, uint16_t *datalen); + void HTTP_POST_end(void); + void setUserAgent(const __FlashStringHelper *useragent); + + // HTTPS + void setHTTPSRedirect(boolean onoff); + + // PWM (buzzer) + boolean setPWM(uint16_t period, uint8_t duty = 50); + + // Phone calls + boolean callPhone(char *phonenum); + boolean hangUp(void); + boolean pickUp(void); + boolean callerIdNotification(boolean enable, uint8_t interrupt = 0); + boolean incomingCallNumber(char* phonenum); + + // Helper functions to verify responses. + boolean expectReply(const __FlashStringHelper *reply, uint16_t timeout = 10000); + boolean sendCheckReply(char *send, char *reply, uint16_t timeout = FONA_DEFAULT_TIMEOUT_MS); + boolean sendCheckReply(const __FlashStringHelper *send, const __FlashStringHelper *reply, uint16_t timeout = FONA_DEFAULT_TIMEOUT_MS); + + + protected: + int8_t _rstpin; + uint8_t _type; + + char replybuffer[255]; + const __FlashStringHelper *apn; + const __FlashStringHelper *apnusername; + const __FlashStringHelper *apnpassword; + boolean httpsredirect; + const __FlashStringHelper *useragent; + + // HTTP helpers + boolean HTTP_setup(char *url); + + void flushInput(); + uint16_t readRaw(uint16_t b); + uint8_t readline(uint16_t timeout = FONA_DEFAULT_TIMEOUT_MS, boolean multiline = false); + uint8_t getReply(char *send, uint16_t timeout = FONA_DEFAULT_TIMEOUT_MS); + uint8_t getReply(const __FlashStringHelper *send, uint16_t timeout = FONA_DEFAULT_TIMEOUT_MS); + uint8_t getReply(const __FlashStringHelper *prefix, char *suffix, uint16_t timeout = FONA_DEFAULT_TIMEOUT_MS); + uint8_t getReply(const __FlashStringHelper *prefix, int32_t suffix, uint16_t timeout = FONA_DEFAULT_TIMEOUT_MS); + uint8_t getReply(const __FlashStringHelper *prefix, int32_t suffix1, int32_t suffix2, uint16_t timeout); // Don't set default value or else function call is ambiguous. + uint8_t getReplyQuoted(const __FlashStringHelper *prefix, const __FlashStringHelper *suffix, uint16_t timeout = FONA_DEFAULT_TIMEOUT_MS); + + boolean sendCheckReply(const __FlashStringHelper *prefix, char *suffix, const __FlashStringHelper *reply, uint16_t timeout = FONA_DEFAULT_TIMEOUT_MS); + boolean sendCheckReply(const __FlashStringHelper *prefix, int32_t suffix, const __FlashStringHelper *reply, uint16_t timeout = FONA_DEFAULT_TIMEOUT_MS); + boolean sendCheckReply(const __FlashStringHelper *prefix, int32_t suffix, int32_t suffix2, const __FlashStringHelper *reply, uint16_t timeout = FONA_DEFAULT_TIMEOUT_MS); + boolean sendCheckReplyQuoted(const __FlashStringHelper *prefix, const __FlashStringHelper *suffix, const __FlashStringHelper *reply, uint16_t timeout = FONA_DEFAULT_TIMEOUT_MS); + + + boolean parseReply(const __FlashStringHelper *toreply, + uint16_t *v, char divider = ',', uint8_t index=0); + boolean parseReply(const __FlashStringHelper *toreply, + char *v, char divider = ',', uint8_t index=0); + boolean parseReplyQuoted(const __FlashStringHelper *toreply, + char *v, int maxlen, char divider, uint8_t index); + + boolean sendParseReply(const __FlashStringHelper *tosend, + const __FlashStringHelper *toreply, + uint16_t *v, char divider = ',', uint8_t index=0); + + static boolean _incomingCall; + static void onIncomingCall(); + + Stream *mySerial; +}; + +class Adafruit_FONA_3G : public Adafruit_FONA { + + public: + Adafruit_FONA_3G (int8_t r) : Adafruit_FONA(r) { _type = FONA3G_A; } + + boolean getBattVoltage(uint16_t *v); + boolean playToolkitTone(uint8_t t, uint16_t len); + boolean hangUp(void); + boolean pickUp(void); + boolean enableGPRS(boolean onoff); + boolean enableGPS(boolean onoff); + + protected: + boolean parseReply(const __FlashStringHelper *toreply, + float *f, char divider, uint8_t index); + + boolean sendParseReply(const __FlashStringHelper *tosend, + const __FlashStringHelper *toreply, + float *f, char divider = ',', uint8_t index=0); +}; + +#endif diff --git a/libraries/Adafruit_FONA_Library/README.md b/libraries/Adafruit_FONA_Library/README.md new file mode 100644 index 0000000..73452ca --- /dev/null +++ b/libraries/Adafruit_FONA_Library/README.md @@ -0,0 +1,29 @@ +# Adafruit FONA Library [![Build Status](https://secure.travis-ci.org/adafruit/Adafruit_FONA_Library.svg?branch=master)](https://travis-ci.org/adafruit/Adafruit_FONA_Library) + +**This library requires Arduino v1.0.6 or higher** + +This is a library for the Adafruit FONA Cellular GSM Breakouts etc + +Designed specifically to work with the Adafruit FONA Breakout + * https://www.adafruit.com/products/1946 + * https://www.adafruit.com/products/1963 + * http://www.adafruit.com/products/2468 + * http://www.adafruit.com/products/2542 + +These modules 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! + +Check out the links above for our tutorials and wiring diagrams + +Written by Limor Fried/Ladyada for Adafruit Industries. +BSD license, all text above must be included in any redistribution +With updates from Samy Kamkar + +To download. click the DOWNLOADS button in the top right corner, rename the uncompressed folder Adafruit_FONA +Check that the Adafruit_FONA folder contains Adafruit_FONA.cpp and Adafruit_FONA.h + +Place the Adafruit_FONA library folder your *arduinosketchfolder*/libraries/ folder. +You may need to create the libraries subfolder if its your first library. Restart the IDE. diff --git a/libraries/Adafruit_FONA_Library/examples/FONA3G_setbaud/.esp8266.test.skip b/libraries/Adafruit_FONA_Library/examples/FONA3G_setbaud/.esp8266.test.skip new file mode 100644 index 0000000..e69de29 diff --git a/libraries/Adafruit_FONA_Library/examples/FONA3G_setbaud/FONA3G_setbaud.ino b/libraries/Adafruit_FONA_Library/examples/FONA3G_setbaud/FONA3G_setbaud.ino new file mode 100644 index 0000000..b0be4c5 --- /dev/null +++ b/libraries/Adafruit_FONA_Library/examples/FONA3G_setbaud/FONA3G_setbaud.ino @@ -0,0 +1,77 @@ +/*************************************************** + This is an example for our Adafruit FONA Cellular Module + since the FONA 3G does not do auto-baud very well, this demo + fixes the baud rate to 4800 from the default 115200 + + Designed specifically to work with the Adafruit FONA 3G + ----> http://www.adafruit.com/products/2691 + ----> http://www.adafruit.com/products/2687 + + These cellular modules 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 + ****************************************************/ + +#include "Adafruit_FONA.h" + +#define FONA_RX 2 +#define FONA_TX 3 +#define FONA_RST 4 + +// this is a large buffer for replies +char replybuffer[255]; + +// We default to using software serial. If you want to use hardware serial +// (because softserial isnt supported) comment out the following three lines +// and uncomment the HardwareSerial line +#include +SoftwareSerial fonaSS = SoftwareSerial(FONA_TX, FONA_RX); +SoftwareSerial *fonaSerial = &fonaSS; + +// Hardware serial is also possible! +// HardwareSerial *fonaSerial = &Serial1; + +Adafruit_FONA fona = Adafruit_FONA(FONA_RST); + +uint8_t readline(char *buff, uint8_t maxbuff, uint16_t timeout = 0); + +void setup() { + while (!Serial); + + Serial.begin(115200); + Serial.println(F("FONA set baudrate")); + + Serial.println(F("First trying 115200 baud")); + // start at 115200 baud + fonaSerial->begin(115200); + fona.begin(*fonaSerial); + + // send the command to reset the baud rate to 4800 + fona.setBaudrate(4800); + + // restart with 4800 baud + fonaSerial->begin(4800); + Serial.println(F("Initializing @ 4800 baud...")); + + if (! fona.begin(*fonaSerial)) { + Serial.println(F("Couldn't find FONA")); + while(1); + } + Serial.println(F("FONA is OK")); + + // Print module IMEI number. + char imei[15] = {0}; // MUST use a 16 character buffer for IMEI! + uint8_t imeiLen = fona.getIMEI(imei); + if (imeiLen > 0) { + Serial.print("Module IMEI: "); Serial.println(imei); + } + +} + +void loop() { +} \ No newline at end of file diff --git a/libraries/Adafruit_FONA_Library/examples/FONA_SMS_Response/.esp8266.test.skip b/libraries/Adafruit_FONA_Library/examples/FONA_SMS_Response/.esp8266.test.skip new file mode 100644 index 0000000..e69de29 diff --git a/libraries/Adafruit_FONA_Library/examples/FONA_SMS_Response/FONA_SMS_Response.ino b/libraries/Adafruit_FONA_Library/examples/FONA_SMS_Response/FONA_SMS_Response.ino new file mode 100644 index 0000000..f1bcf66 --- /dev/null +++ b/libraries/Adafruit_FONA_Library/examples/FONA_SMS_Response/FONA_SMS_Response.ino @@ -0,0 +1,122 @@ +/*************************************************** + This is an example 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 + ----> http://www.adafruit.com/products/2468 + ----> http://www.adafruit.com/products/2542 + + These cellular modules 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 + ****************************************************/ + +/* +THIS CODE IS STILL IN PROGRESS! + +Open up the serial console on the Arduino at 115200 baud to interact with FONA + + +This code will receive an SMS, identify the sender's phone number, and automatically send a response + +*/ + +#include "Adafruit_FONA.h" + +#define FONA_RX 2 +#define FONA_TX 3 +#define FONA_RST 4 + +// this is a large buffer for replies +char replybuffer[255]; + +// We default to using software serial. If you want to use hardware serial +// (because softserial isnt supported) comment out the following three lines +// and uncomment the HardwareSerial line +#include +SoftwareSerial fonaSS = SoftwareSerial(FONA_TX, FONA_RX); +SoftwareSerial *fonaSerial = &fonaSS; + +// Hardware serial is also possible! +// HardwareSerial *fonaSerial = &Serial1; + +Adafruit_FONA fona = Adafruit_FONA(FONA_RST); + +uint8_t readline(char *buff, uint8_t maxbuff, uint16_t timeout = 0); + +void setup() { + while (!Serial); + + Serial.begin(115200); + Serial.println(F("FONA SMS caller ID test")); + Serial.println(F("Initializing....(May take 3 seconds)")); + + // make it slow so its easy to read! + fonaSerial->begin(4800); + if (! fona.begin(*fonaSerial)) { + Serial.println(F("Couldn't find FONA")); + while(1); + } + Serial.println(F("FONA is OK")); + + // Print SIM card IMEI number. + char imei[15] = {0}; // MUST use a 16 character buffer for IMEI! + uint8_t imeiLen = fona.getIMEI(imei); + if (imeiLen > 0) { + Serial.print("SIM card IMEI: "); Serial.println(imei); + } + + Serial.println("FONA Ready"); +} + + +char fonaInBuffer[64]; //for notifications from the FONA + +void loop() { + + char* bufPtr = fonaInBuffer; //handy buffer pointer + + if (fona.available()) //any data available from the FONA? + { + int slot = 0; //this will be the slot number of the SMS + int charCount = 0; + //Read the notification into fonaInBuffer + do { + *bufPtr = fona.read(); + Serial.write(*bufPtr); + delay(1); + } while ((*bufPtr++ != '\n') && (fona.available()) && (++charCount < (sizeof(fonaInBuffer)-1))); + + //Add a terminal NULL to the notification string + *bufPtr = 0; + + //Scan the notification string for an SMS received notification. + // If it's an SMS message, we'll get the slot number in 'slot' + if (1 == sscanf(fonaInBuffer, "+CMTI: \"SM\",%d", &slot)) { + Serial.print("slot: "); Serial.println(slot); + + char callerIDbuffer[32]; //we'll store the SMS sender number in here + + // Retrieve SMS sender address/phone number. + if (! fona.getSMSSender(slot, callerIDbuffer, 31)) { + Serial.println("Didn't find SMS message in slot!"); + } + Serial.print(F("FROM: ")); Serial.println(callerIDbuffer); + + //Send back an automatic response + Serial.println("Sending reponse..."); + if (!fona.sendSMS(callerIDbuffer, "Hey, I got your text!")) { + Serial.println(F("Failed")); + } else { + Serial.println(F("Sent!")); + } + + } + } +} diff --git a/libraries/Adafruit_FONA_Library/examples/FONAtest/.esp8266.test.skip b/libraries/Adafruit_FONA_Library/examples/FONAtest/.esp8266.test.skip new file mode 100644 index 0000000..e69de29 diff --git a/libraries/Adafruit_FONA_Library/examples/FONAtest/FONAtest.ino b/libraries/Adafruit_FONA_Library/examples/FONAtest/FONAtest.ino new file mode 100644 index 0000000..fea4f9e --- /dev/null +++ b/libraries/Adafruit_FONA_Library/examples/FONAtest/FONAtest.ino @@ -0,0 +1,851 @@ +/*************************************************** + This is an example 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 + ----> http://www.adafruit.com/products/2468 + ----> http://www.adafruit.com/products/2542 + + These cellular modules 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 + ****************************************************/ + +/* +THIS CODE IS STILL IN PROGRESS! + +Open up the serial console on the Arduino at 115200 baud to interact with FONA + +Note that if you need to set a GPRS APN, username, and password scroll down to +the commented section below at the end of the setup() function. +*/ +#include "Adafruit_FONA.h" + +#define FONA_RX 2 +#define FONA_TX 3 +#define FONA_RST 4 + +// this is a large buffer for replies +char replybuffer[255]; + +// We default to using software serial. If you want to use hardware serial +// (because softserial isnt supported) comment out the following three lines +// and uncomment the HardwareSerial line +#include +SoftwareSerial fonaSS = SoftwareSerial(FONA_TX, FONA_RX); +SoftwareSerial *fonaSerial = &fonaSS; + +// Hardware serial is also possible! +// HardwareSerial *fonaSerial = &Serial1; + +// Use this for FONA 800 and 808s +Adafruit_FONA fona = Adafruit_FONA(FONA_RST); +// Use this one for FONA 3G +//Adafruit_FONA_3G fona = Adafruit_FONA_3G(FONA_RST); + +uint8_t readline(char *buff, uint8_t maxbuff, uint16_t timeout = 0); + +uint8_t type; + +void setup() { + while (!Serial); + + Serial.begin(115200); + Serial.println(F("FONA basic test")); + Serial.println(F("Initializing....(May take 3 seconds)")); + + fonaSerial->begin(4800); + if (! fona.begin(*fonaSerial)) { + Serial.println(F("Couldn't find FONA")); + while (1); + } + type = fona.type(); + Serial.println(F("FONA is OK")); + Serial.print(F("Found ")); + switch (type) { + case FONA800L: + Serial.println(F("FONA 800L")); break; + case FONA800H: + Serial.println(F("FONA 800H")); break; + case FONA808_V1: + Serial.println(F("FONA 808 (v1)")); break; + case FONA808_V2: + Serial.println(F("FONA 808 (v2)")); break; + case FONA3G_A: + Serial.println(F("FONA 3G (American)")); break; + case FONA3G_E: + Serial.println(F("FONA 3G (European)")); break; + default: + Serial.println(F("???")); break; + } + + // Print module IMEI number. + char imei[15] = {0}; // MUST use a 16 character buffer for IMEI! + uint8_t imeiLen = fona.getIMEI(imei); + if (imeiLen > 0) { + Serial.print("Module IMEI: "); Serial.println(imei); + } + + // Optionally configure a GPRS APN, username, and password. + // You might need to do this to access your network's GPRS/data + // network. Contact your provider for the exact APN, username, + // and password values. Username and password are optional and + // can be removed, but APN is required. + //fona.setGPRSNetworkSettings(F("your APN"), F("your username"), F("your password")); + + // Optionally configure HTTP gets to follow redirects over SSL. + // Default is not to follow SSL redirects, however if you uncomment + // the following line then redirects over SSL will be followed. + //fona.setHTTPSRedirect(true); + + printMenu(); +} + +void printMenu(void) { + Serial.println(F("-------------------------------------")); + Serial.println(F("[?] Print this menu")); + Serial.println(F("[a] read the ADC 2.8V max (FONA800 & 808)")); + Serial.println(F("[b] read the Battery V and % charged")); + Serial.println(F("[C] read the SIM CCID")); + Serial.println(F("[U] Unlock SIM with PIN code")); + Serial.println(F("[i] read RSSI")); + Serial.println(F("[n] get Network status")); + Serial.println(F("[v] set audio Volume")); + Serial.println(F("[V] get Volume")); + Serial.println(F("[H] set Headphone audio (FONA800 & 808)")); + Serial.println(F("[e] set External audio (FONA800 & 808)")); + Serial.println(F("[T] play audio Tone")); + Serial.println(F("[P] PWM/Buzzer out (FONA800 & 808)")); + + // FM (SIM800 only!) + Serial.println(F("[f] tune FM radio (FONA800)")); + Serial.println(F("[F] turn off FM (FONA800)")); + Serial.println(F("[m] set FM volume (FONA800)")); + Serial.println(F("[M] get FM volume (FONA800)")); + Serial.println(F("[q] get FM station signal level (FONA800)")); + + // Phone + Serial.println(F("[c] make phone Call")); + Serial.println(F("[h] Hang up phone")); + Serial.println(F("[p] Pick up phone")); + + // SMS + Serial.println(F("[N] Number of SMSs")); + Serial.println(F("[r] Read SMS #")); + Serial.println(F("[R] Read All SMS")); + Serial.println(F("[d] Delete SMS #")); + Serial.println(F("[s] Send SMS")); + + // Time + Serial.println(F("[y] Enable network time sync (FONA 800 & 808)")); + Serial.println(F("[Y] Enable NTP time sync (GPRS FONA 800 & 808)")); + Serial.println(F("[t] Get network time")); + + // GPRS + Serial.println(F("[G] Enable GPRS")); + Serial.println(F("[g] Disable GPRS")); + Serial.println(F("[l] Query GSMLOC (GPRS)")); + Serial.println(F("[w] Read webpage (GPRS)")); + Serial.println(F("[W] Post to website (GPRS)")); + + // GPS + if ((type == FONA3G_A) || (type == FONA3G_E) || (type == FONA808_V1) || (type == FONA808_V2)) { + Serial.println(F("[O] Turn GPS on (FONA 808 & 3G)")); + Serial.println(F("[o] Turn GPS off (FONA 808 & 3G)")); + Serial.println(F("[L] Query GPS location (FONA 808 & 3G)")); + if (type == FONA808_V1) { + Serial.println(F("[x] GPS fix status (FONA808 v1 only)")); + } + Serial.println(F("[E] Raw NMEA out (FONA808)")); + } + + Serial.println(F("[S] create Serial passthru tunnel")); + Serial.println(F("-------------------------------------")); + Serial.println(F("")); + +} +void loop() { + Serial.print(F("FONA> ")); + while (! Serial.available() ) { + if (fona.available()) { + Serial.write(fona.read()); + } + } + + char command = Serial.read(); + Serial.println(command); + + + switch (command) { + case '?': { + printMenu(); + break; + } + + case 'a': { + // read the ADC + uint16_t adc; + if (! fona.getADCVoltage(&adc)) { + Serial.println(F("Failed to read ADC")); + } else { + Serial.print(F("ADC = ")); Serial.print(adc); Serial.println(F(" mV")); + } + break; + } + + case 'b': { + // read the battery voltage and percentage + uint16_t vbat; + if (! fona.getBattVoltage(&vbat)) { + Serial.println(F("Failed to read Batt")); + } else { + Serial.print(F("VBat = ")); Serial.print(vbat); Serial.println(F(" mV")); + } + + + if (! fona.getBattPercent(&vbat)) { + Serial.println(F("Failed to read Batt")); + } else { + Serial.print(F("VPct = ")); Serial.print(vbat); Serial.println(F("%")); + } + + break; + } + + case 'U': { + // Unlock the SIM with a PIN code + char PIN[5]; + flushSerial(); + Serial.println(F("Enter 4-digit PIN")); + readline(PIN, 3); + Serial.println(PIN); + Serial.print(F("Unlocking SIM card: ")); + if (! fona.unlockSIM(PIN)) { + Serial.println(F("Failed")); + } else { + Serial.println(F("OK!")); + } + break; + } + + case 'C': { + // read the CCID + fona.getSIMCCID(replybuffer); // make sure replybuffer is at least 21 bytes! + Serial.print(F("SIM CCID = ")); Serial.println(replybuffer); + break; + } + + case 'i': { + // read the RSSI + uint8_t n = fona.getRSSI(); + int8_t r; + + Serial.print(F("RSSI = ")); Serial.print(n); Serial.print(": "); + if (n == 0) r = -115; + if (n == 1) r = -111; + if (n == 31) r = -52; + if ((n >= 2) && (n <= 30)) { + r = map(n, 2, 30, -110, -54); + } + Serial.print(r); Serial.println(F(" dBm")); + + break; + } + + case 'n': { + // read the network/cellular status + uint8_t n = fona.getNetworkStatus(); + Serial.print(F("Network status ")); + Serial.print(n); + Serial.print(F(": ")); + if (n == 0) Serial.println(F("Not registered")); + if (n == 1) Serial.println(F("Registered (home)")); + if (n == 2) Serial.println(F("Not registered (searching)")); + if (n == 3) Serial.println(F("Denied")); + if (n == 4) Serial.println(F("Unknown")); + if (n == 5) Serial.println(F("Registered roaming")); + break; + } + + /*** Audio ***/ + case 'v': { + // set volume + flushSerial(); + if ( (type == FONA3G_A) || (type == FONA3G_E) ) { + Serial.print(F("Set Vol [0-8] ")); + } else { + Serial.print(F("Set Vol % [0-100] ")); + } + uint8_t vol = readnumber(); + Serial.println(); + if (! fona.setVolume(vol)) { + Serial.println(F("Failed")); + } else { + Serial.println(F("OK!")); + } + break; + } + + case 'V': { + uint8_t v = fona.getVolume(); + Serial.print(v); + if ( (type == FONA3G_A) || (type == FONA3G_E) ) { + Serial.println(" / 8"); + } else { + Serial.println("%"); + } + break; + } + + case 'H': { + // Set Headphone output + if (! fona.setAudio(FONA_HEADSETAUDIO)) { + Serial.println(F("Failed")); + } else { + Serial.println(F("OK!")); + } + fona.setMicVolume(FONA_HEADSETAUDIO, 15); + break; + } + case 'e': { + // Set External output + if (! fona.setAudio(FONA_EXTAUDIO)) { + Serial.println(F("Failed")); + } else { + Serial.println(F("OK!")); + } + + fona.setMicVolume(FONA_EXTAUDIO, 10); + break; + } + + case 'T': { + // play tone + flushSerial(); + Serial.print(F("Play tone #")); + uint8_t kittone = readnumber(); + Serial.println(); + // play for 1 second (1000 ms) + if (! fona.playToolkitTone(kittone, 1000)) { + Serial.println(F("Failed")); + } else { + Serial.println(F("OK!")); + } + break; + } + + /*** FM Radio ***/ + + case 'f': { + // get freq + flushSerial(); + Serial.print(F("FM Freq (eg 1011 == 101.1 MHz): ")); + uint16_t station = readnumber(); + Serial.println(); + // FM radio ON using headset + if (fona.FMradio(true, FONA_HEADSETAUDIO)) { + Serial.println(F("Opened")); + } + if (! fona.tuneFMradio(station)) { + Serial.println(F("Failed")); + } else { + Serial.println(F("Tuned")); + } + break; + } + case 'F': { + // FM radio off + if (! fona.FMradio(false)) { + Serial.println(F("Failed")); + } else { + Serial.println(F("OK!")); + } + break; + } + case 'm': { + // Set FM volume. + flushSerial(); + Serial.print(F("Set FM Vol [0-6]:")); + uint8_t vol = readnumber(); + Serial.println(); + if (!fona.setFMVolume(vol)) { + Serial.println(F("Failed")); + } else { + Serial.println(F("OK!")); + } + break; + } + case 'M': { + // Get FM volume. + uint8_t fmvol = fona.getFMVolume(); + if (fmvol < 0) { + Serial.println(F("Failed")); + } else { + Serial.print(F("FM volume: ")); + Serial.println(fmvol, DEC); + } + break; + } + case 'q': { + // Get FM station signal level (in decibels). + flushSerial(); + Serial.print(F("FM Freq (eg 1011 == 101.1 MHz): ")); + uint16_t station = readnumber(); + Serial.println(); + int8_t level = fona.getFMSignalLevel(station); + if (level < 0) { + Serial.println(F("Failed! Make sure FM radio is on (tuned to station).")); + } else { + Serial.print(F("Signal level (dB): ")); + Serial.println(level, DEC); + } + break; + } + + /*** PWM ***/ + + case 'P': { + // PWM Buzzer output @ 2KHz max + flushSerial(); + Serial.print(F("PWM Freq, 0 = Off, (1-2000): ")); + uint16_t freq = readnumber(); + Serial.println(); + if (! fona.setPWM(freq)) { + Serial.println(F("Failed")); + } else { + Serial.println(F("OK!")); + } + break; + } + + /*** Call ***/ + case 'c': { + // call a phone! + char number[30]; + flushSerial(); + Serial.print(F("Call #")); + readline(number, 30); + Serial.println(); + Serial.print(F("Calling ")); Serial.println(number); + if (!fona.callPhone(number)) { + Serial.println(F("Failed")); + } else { + Serial.println(F("Sent!")); + } + + break; + } + case 'h': { + // hang up! + if (! fona.hangUp()) { + Serial.println(F("Failed")); + } else { + Serial.println(F("OK!")); + } + break; + } + + case 'p': { + // pick up! + if (! fona.pickUp()) { + Serial.println(F("Failed")); + } else { + Serial.println(F("OK!")); + } + break; + } + + /*** SMS ***/ + + case 'N': { + // read the number of SMS's! + int8_t smsnum = fona.getNumSMS(); + if (smsnum < 0) { + Serial.println(F("Could not read # SMS")); + } else { + Serial.print(smsnum); + Serial.println(F(" SMS's on SIM card!")); + } + break; + } + case 'r': { + // read an SMS + flushSerial(); + Serial.print(F("Read #")); + uint8_t smsn = readnumber(); + Serial.print(F("\n\rReading SMS #")); Serial.println(smsn); + + // Retrieve SMS sender address/phone number. + if (! fona.getSMSSender(smsn, replybuffer, 250)) { + Serial.println("Failed!"); + break; + } + Serial.print(F("FROM: ")); Serial.println(replybuffer); + + // Retrieve SMS value. + uint16_t smslen; + if (! fona.readSMS(smsn, replybuffer, 250, &smslen)) { // pass in buffer and max len! + Serial.println("Failed!"); + break; + } + Serial.print(F("***** SMS #")); Serial.print(smsn); + Serial.print(" ("); Serial.print(smslen); Serial.println(F(") bytes *****")); + Serial.println(replybuffer); + Serial.println(F("*****")); + + break; + } + case 'R': { + // read all SMS + int8_t smsnum = fona.getNumSMS(); + uint16_t smslen; + int8_t smsn; + + if ( (type == FONA3G_A) || (type == FONA3G_E) ) { + smsn = 0; // zero indexed + smsnum--; + } else { + smsn = 1; // 1 indexed + } + + for ( ; smsn <= smsnum; smsn++) { + Serial.print(F("\n\rReading SMS #")); Serial.println(smsn); + if (!fona.readSMS(smsn, replybuffer, 250, &smslen)) { // pass in buffer and max len! + Serial.println(F("Failed!")); + break; + } + // if the length is zero, its a special case where the index number is higher + // so increase the max we'll look at! + if (smslen == 0) { + Serial.println(F("[empty slot]")); + smsnum++; + continue; + } + + Serial.print(F("***** SMS #")); Serial.print(smsn); + Serial.print(" ("); Serial.print(smslen); Serial.println(F(") bytes *****")); + Serial.println(replybuffer); + Serial.println(F("*****")); + } + break; + } + + case 'd': { + // delete an SMS + flushSerial(); + Serial.print(F("Delete #")); + uint8_t smsn = readnumber(); + + Serial.print(F("\n\rDeleting SMS #")); Serial.println(smsn); + if (fona.deleteSMS(smsn)) { + Serial.println(F("OK!")); + } else { + Serial.println(F("Couldn't delete")); + } + break; + } + + case 's': { + // send an SMS! + char sendto[21], message[141]; + flushSerial(); + Serial.print(F("Send to #")); + readline(sendto, 20); + Serial.println(sendto); + Serial.print(F("Type out one-line message (140 char): ")); + readline(message, 140); + Serial.println(message); + if (!fona.sendSMS(sendto, message)) { + Serial.println(F("Failed")); + } else { + Serial.println(F("Sent!")); + } + + break; + } + + /*** Time ***/ + + case 'y': { + // enable network time sync + if (!fona.enableNetworkTimeSync(true)) + Serial.println(F("Failed to enable")); + break; + } + + case 'Y': { + // enable NTP time sync + if (!fona.enableNTPTimeSync(true, F("pool.ntp.org"))) + Serial.println(F("Failed to enable")); + break; + } + + case 't': { + // read the time + char buffer[23]; + + fona.getTime(buffer, 23); // make sure replybuffer is at least 23 bytes! + Serial.print(F("Time = ")); Serial.println(buffer); + break; + } + + + /*********************************** GPS (SIM808 only) */ + + case 'o': { + // turn GPS off + if (!fona.enableGPS(false)) + Serial.println(F("Failed to turn off")); + break; + } + case 'O': { + // turn GPS on + if (!fona.enableGPS(true)) + Serial.println(F("Failed to turn on")); + break; + } + case 'x': { + int8_t stat; + // check GPS fix + stat = fona.GPSstatus(); + if (stat < 0) + Serial.println(F("Failed to query")); + if (stat == 0) Serial.println(F("GPS off")); + if (stat == 1) Serial.println(F("No fix")); + if (stat == 2) Serial.println(F("2D fix")); + if (stat == 3) Serial.println(F("3D fix")); + break; + } + + case 'L': { + // check for GPS location + char gpsdata[120]; + fona.getGPS(0, gpsdata, 120); + if (type == FONA808_V1) + Serial.println(F("Reply in format: mode,longitude,latitude,altitude,utctime(yyyymmddHHMMSS),ttff,satellites,speed,course")); + else + Serial.println(F("Reply in format: mode,fixstatus,utctime(yyyymmddHHMMSS),latitude,longitude,altitude,speed,course,fixmode,reserved1,HDOP,PDOP,VDOP,reserved2,view_satellites,used_satellites,reserved3,C/N0max,HPA,VPA")); + Serial.println(gpsdata); + + break; + } + + case 'E': { + flushSerial(); + if (type == FONA808_V1) { + Serial.print(F("GPS NMEA output sentences (0 = off, 34 = RMC+GGA, 255 = all)")); + } else { + Serial.print(F("On (1) or Off (0)? ")); + } + uint8_t nmeaout = readnumber(); + + // turn on NMEA output + fona.enableGPSNMEA(nmeaout); + + break; + } + + /*********************************** GPRS */ + + case 'g': { + // turn GPRS off + if (!fona.enableGPRS(false)) + Serial.println(F("Failed to turn off")); + break; + } + case 'G': { + // turn GPRS on + if (!fona.enableGPRS(true)) + Serial.println(F("Failed to turn on")); + break; + } + case 'l': { + // check for GSMLOC (requires GPRS) + uint16_t returncode; + + if (!fona.getGSMLoc(&returncode, replybuffer, 250)) + Serial.println(F("Failed!")); + if (returncode == 0) { + Serial.println(replybuffer); + } else { + Serial.print(F("Fail code #")); Serial.println(returncode); + } + + break; + } + case 'w': { + // read website URL + uint16_t statuscode; + int16_t length; + char url[80]; + + flushSerial(); + Serial.println(F("NOTE: in beta! Use small webpages to read!")); + Serial.println(F("URL to read (e.g. www.adafruit.com/testwifi/index.html):")); + Serial.print(F("http://")); readline(url, 79); + Serial.println(url); + + Serial.println(F("****")); + if (!fona.HTTP_GET_start(url, &statuscode, (uint16_t *)&length)) { + Serial.println("Failed!"); + break; + } + while (length > 0) { + while (fona.available()) { + char c = fona.read(); + + // Serial.write is too slow, we'll write directly to Serial register! +#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) + loop_until_bit_is_set(UCSR0A, UDRE0); /* Wait until data register empty. */ + UDR0 = c; +#else + Serial.write(c); +#endif + length--; + if (! length) break; + } + } + Serial.println(F("\n****")); + fona.HTTP_GET_end(); + break; + } + + case 'W': { + // Post data to website + uint16_t statuscode; + int16_t length; + char url[80]; + char data[80]; + + flushSerial(); + Serial.println(F("NOTE: in beta! Use simple websites to post!")); + Serial.println(F("URL to post (e.g. httpbin.org/post):")); + Serial.print(F("http://")); readline(url, 79); + Serial.println(url); + Serial.println(F("Data to post (e.g. \"foo\" or \"{\"simple\":\"json\"}\"):")); + readline(data, 79); + Serial.println(data); + + Serial.println(F("****")); + if (!fona.HTTP_POST_start(url, F("text/plain"), (uint8_t *) data, strlen(data), &statuscode, (uint16_t *)&length)) { + Serial.println("Failed!"); + break; + } + while (length > 0) { + while (fona.available()) { + char c = fona.read(); + +#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) + loop_until_bit_is_set(UCSR0A, UDRE0); /* Wait until data register empty. */ + UDR0 = c; +#else + Serial.write(c); +#endif + + length--; + if (! length) break; + } + } + Serial.println(F("\n****")); + fona.HTTP_POST_end(); + break; + } + /*****************************************/ + + case 'S': { + Serial.println(F("Creating SERIAL TUBE")); + while (1) { + while (Serial.available()) { + delay(1); + fona.write(Serial.read()); + } + if (fona.available()) { + Serial.write(fona.read()); + } + } + break; + } + + default: { + Serial.println(F("Unknown command")); + printMenu(); + break; + } + } + // flush input + flushSerial(); + while (fona.available()) { + Serial.write(fona.read()); + } + +} + +void flushSerial() { + while (Serial.available()) + Serial.read(); +} + +char readBlocking() { + while (!Serial.available()); + return Serial.read(); +} +uint16_t readnumber() { + uint16_t x = 0; + char c; + while (! isdigit(c = readBlocking())) { + //Serial.print(c); + } + Serial.print(c); + x = c - '0'; + while (isdigit(c = readBlocking())) { + Serial.print(c); + x *= 10; + x += c - '0'; + } + return x; +} + +uint8_t readline(char *buff, uint8_t maxbuff, uint16_t timeout) { + uint16_t buffidx = 0; + boolean timeoutvalid = true; + if (timeout == 0) timeoutvalid = false; + + while (true) { + if (buffidx > maxbuff) { + //Serial.println(F("SPACE")); + break; + } + + while (Serial.available()) { + char c = Serial.read(); + + //Serial.print(c, HEX); Serial.print("#"); Serial.println(c); + + if (c == '\r') continue; + if (c == 0xA) { + if (buffidx == 0) // the first 0x0A is ignored + continue; + + timeout = 0; // the second 0x0A is the end of the line + timeoutvalid = true; + break; + } + buff[buffidx] = c; + buffidx++; + } + + if (timeoutvalid && timeout == 0) { + //Serial.println(F("TIMEOUT")); + break; + } + delay(1); + } + buff[buffidx] = 0; // null term + return buffidx; +} diff --git a/libraries/Adafruit_FONA_Library/examples/GPS/.esp8266.test.skip b/libraries/Adafruit_FONA_Library/examples/GPS/.esp8266.test.skip new file mode 100644 index 0000000..e69de29 diff --git a/libraries/Adafruit_FONA_Library/examples/GPS/GPS.ino b/libraries/Adafruit_FONA_Library/examples/GPS/GPS.ino new file mode 100644 index 0000000..cce63d5 --- /dev/null +++ b/libraries/Adafruit_FONA_Library/examples/GPS/GPS.ino @@ -0,0 +1,112 @@ +/** + * ___ ___ _ _ _ ___ __ ___ ___ ___ ___ + * | __/ _ \| \| | /_\ ( _ )/ \( _ ) / __| _ \/ __| + * | _| (_) | .` |/ _ \ / _ \ () / _ \ | (_ | _/\__ \ + * |_| \___/|_|\_/_/ \_\ \___/\__/\___/ \___|_| |___/ + * + * This example is meant to work with the Adafruit + * FONA 808 or 3G Shield or Breakout + * + * Copyright: 2015 Adafruit + * Author: Todd Treece + * Licence: MIT + * + */ +#include "Adafruit_FONA.h" + +// standard pins for the shield, adjust as necessary +#define FONA_RX 2 +#define FONA_TX 3 +#define FONA_RST 4 + +// We default to using software serial. If you want to use hardware serial +// (because softserial isnt supported) comment out the following three lines +// and uncomment the HardwareSerial line +#include +SoftwareSerial fonaSS = SoftwareSerial(FONA_TX, FONA_RX); +SoftwareSerial *fonaSerial = &fonaSS; + +// Hardware serial is also possible! +// HardwareSerial *fonaSerial = &Serial1; + +Adafruit_FONA fona = Adafruit_FONA(FONA_RST); + +// Have a FONA 3G? use this object type instead +//Adafruit_FONA_3G fona = Adafruit_FONA_3G(FONA_RST); + + +void setup() { + + while (! Serial); + + Serial.begin(115200); + Serial.println(F("Adafruit FONA 808 & 3G GPS demo")); + Serial.println(F("Initializing FONA... (May take a few seconds)")); + + fonaSerial->begin(4800); + if (! fona.begin(*fonaSerial)) { + Serial.println(F("Couldn't find FONA")); + while(1); + } + Serial.println(F("FONA is OK")); + // Try to enable GPRS + + + Serial.println(F("Enabling GPS...")); + fona.enableGPS(true); +} + +void loop() { + delay(2000); + + float latitude, longitude, speed_kph, heading, speed_mph, altitude; + + // if you ask for an altitude reading, getGPS will return false if there isn't a 3D fix + boolean gps_success = fona.getGPS(&latitude, &longitude, &speed_kph, &heading, &altitude); + + if (gps_success) { + + Serial.print("GPS lat:"); + Serial.println(latitude, 6); + Serial.print("GPS long:"); + Serial.println(longitude, 6); + Serial.print("GPS speed KPH:"); + Serial.println(speed_kph); + Serial.print("GPS speed MPH:"); + speed_mph = speed_kph * 0.621371192; + Serial.println(speed_mph); + Serial.print("GPS heading:"); + Serial.println(heading); + Serial.print("GPS altitude:"); + Serial.println(altitude); + + } else { + Serial.println("Waiting for FONA GPS 3D fix..."); + } + + // Fona 3G doesnt have GPRSlocation :/ + if ((fona.type() == FONA3G_A) || (fona.type() == FONA3G_E)) + return; + // Check for network, then GPRS + Serial.println(F("Checking for Cell network...")); + if (fona.getNetworkStatus() == 1) { + // network & GPRS? Great! Print out the GSM location to compare + boolean gsmloc_success = fona.getGSMLoc(&latitude, &longitude); + + if (gsmloc_success) { + Serial.print("GSMLoc lat:"); + Serial.println(latitude, 6); + Serial.print("GSMLoc long:"); + Serial.println(longitude, 6); + } else { + Serial.println("GSM location failed..."); + Serial.println(F("Disabling GPRS")); + fona.enableGPRS(false); + Serial.println(F("Enabling GPRS")); + if (!fona.enableGPRS(true)) { + Serial.println(F("Failed to turn GPRS on")); + } + } + } +} + diff --git a/libraries/Adafruit_FONA_Library/examples/IncomingCall/.esp8266.test.skip b/libraries/Adafruit_FONA_Library/examples/IncomingCall/.esp8266.test.skip new file mode 100644 index 0000000..e69de29 diff --git a/libraries/Adafruit_FONA_Library/examples/IncomingCall/IncomingCall.ino b/libraries/Adafruit_FONA_Library/examples/IncomingCall/IncomingCall.ino new file mode 100644 index 0000000..8dba308 --- /dev/null +++ b/libraries/Adafruit_FONA_Library/examples/IncomingCall/IncomingCall.ino @@ -0,0 +1,62 @@ +// FONA Incoming Call Number Example +// Listens for a call and displays the phone number of the caller (if available). +// Use this example to add phone call detection to your own FONA sketch. +#include "Adafruit_FONA.h" + +// Pins which are connected to the FONA. +// Note that this is different from FONAtest! +#define FONA_RX 3 +#define FONA_TX 4 +#define FONA_RST 5 + +// Note you need to map interrupt number to pin number +// for your board. On an Uno & Mega interrupt 0 is +// digital pin 2, and on a Leonardo interrupt 0 is +// digital pin 3. See this page for a complete table: +// http://arduino.cc/en/Reference/attachInterrupt +// Make sure this interrupt pin is connected to FONA RI! +#define FONA_RI_INTERRUPT 0 + +// We default to using software serial. If you want to use hardware serial +// (because softserial isnt supported) comment out the following three lines +// and uncomment the HardwareSerial line +#include +SoftwareSerial fonaSS = SoftwareSerial(FONA_TX, FONA_RX); +SoftwareSerial *fonaSerial = &fonaSS; + +// Hardware serial is also possible! +// HardwareSerial *fonaSerial = &Serial1; + +Adafruit_FONA fona = Adafruit_FONA(FONA_RST); + +void setup() { + Serial.begin(115200); + Serial.println(F("FONA incoming call example")); + Serial.println(F("Initializing....(May take 3 seconds)")); + + fonaSerial->begin(4800); + if (! fona.begin(*fonaSerial)) { + Serial.println(F("Couldn't find FONA")); + while(1); + } + Serial.println(F("FONA is OK")); + + // Enable incoming call notification. + if(fona.callerIdNotification(true, FONA_RI_INTERRUPT)) { + Serial.println(F("Caller id notification enabled.")); + } + else { + Serial.println(F("Caller id notification disabled")); + } +} + +void loop(){ + // Create a small string buffer to hold incoming call number. + char phone[32] = {0}; + // Check for an incoming call. Will return true if a call is incoming. + if(fona.incomingCallNumber(phone)){ + Serial.println(F("RING!")); + Serial.print(F("Phone Number: ")); + Serial.println(phone); + } +} diff --git a/libraries/Adafruit_FONA_Library/library.properties b/libraries/Adafruit_FONA_Library/library.properties new file mode 100644 index 0000000..973c059 --- /dev/null +++ b/libraries/Adafruit_FONA_Library/library.properties @@ -0,0 +1,9 @@ +name=Adafruit FONA Library +version=1.3.0 +author=Adafruit +maintainer=Adafruit +sentence=Arduino library for the Adafruit FONA +paragraph=Arduino library for the Adafruit FONA +category=Communication +url=https://github.com/adafruit/Adafruit_FONA_Library +architectures=* diff --git a/libraries/MySensors/examples/SMSGatewayNode/SMSGatewayNode.ino b/libraries/MySensors/examples/SMSGatewayNode/SMSGatewayNode.ino new file mode 100644 index 0000000..c4daf73 --- /dev/null +++ b/libraries/MySensors/examples/SMSGatewayNode/SMSGatewayNode.ino @@ -0,0 +1,646 @@ +/* + SMS Gateway + + This node works as a SMS gateway, receiving and sending SMS messages at the request of other nodes + It needs to have a fixed ID to be able to be addessed within a MySensors network. + As it is easy to remember I chose the ID 123. + + Once the node is sent an initiating SMS, it will respond to the received calling number as it's "owner". This way you do not + need to hardcode your number in the sketch. But to make it operational, you will need to send at least 1 SMS to it + with the prededfined text MYPASSWORD (see below in the definitions, you set your own string). + The node should respond with CONFIRMOWNER, you can set this string in de definitions below. + The allow another phone to control the node and receive messages, the "owner" needs to release the node by sending a SMS with + the text MYRELEASEWORD. Again you can set this string in the definitions below. + The node will then again become ownerless and ignore all messages and SMS's. + + If the node has an owner and another phone sends a message to the node, it will inform the owner of a "take over attempt". + + You can sent V_TEXT to other nodes in your network by using the following format: + + "N021:xxx.any.25.characters.xxx" + + Anything sent after the "N021:" will be sent to the node with address 021. A V_TEXT has a maximum length of 25 charters. Adding the node address make the SMS length 30 charters. + The SMS buffer is 31 characters long. + + A node address can have a value 000 (the controller) and any value between 001 and 254. Values higher then 254 are ignored and nothing will be done with the + received SMS, apart from informing the controller that this SMS was received. + + Sending a SMS to the SMS Gateway with the address of the SMS Gateway itself will result in the SMS Gateway sending the same SMS back. + So if you send the following SMS to your SMS Gateway: + "N123:Are you there ?" + You will receive a SMS with the content ""N123:Are you there ?" + + What is happening ? + + The SMS Gateway receives a SMS adressed to the node 123, the SMS Gateway sends a copy of the received SMS to the controller and sends a message with content "Are you there ?" + to the node 123. Since node 123 is the SMS Gateway receiving a message, it will pass on this message as a SMS to the owner in the format specified earlier. + So a text SMS is sent with content "N123:Are you there?" + + If a node sends a V_TEXT "Garagedoor is opened" to the SMS Gateway, the SMS gateway will pass this on to the owner's GSM in the format below: + "N011:Garagedoor is opened" + Address from the node sending the text is sent first (in this case "N011:"), and then the contents of the V_TEXT itself is appended ("Garagedoor is opened"). + + You need a SIM800L module hooked to an atmega328 based MySensor node via softserial port. This sketch was made for my AC capable + board wich allows use of a SIM800L module. More on that board on the forum at this location: + http://forum.mysensors.org/topic/2374/50mm-x-50mm-board-with-different-powering-options/10 + or + https://www.openhardware.io/view/11/ACDCBatteries-capable-atmega328p-board + + Nodes that want to inform an GSM owner via the SMS Gateway need to have the capacity to send a V_TEXT. + Even nodes that sleep most of the time can send messages to any other node. You just need to define a V_TEXT message type. + + Nodes that need to react to SMS messages with instructions, need to be able to receive V_TEXT and need to be reachable (always on). + So battery based nodes will not be the best candidates as actuators based on SMS. + + This example code is in the public domain. + + modified 10 oktober 2015 version 1.0 + modified 6 january 2016 version 1.1 + modified 15 january 2016 version 1.2 + + by GertSanders on the MySensors forum + + Uses the Adafruit FONA library to drive the SIM800L, this need to be included in your library to compile this sketch. + + + To do: create a buffer structure to handle several incoming messages from nodes or phone. + + +*/ + +#define SKETCHNAME "SMSGatewayNode" +#define SKETCHVERSION "1.2" + + +// Enable debug prints to serial monitor + +//#define MY_DEBUG +//#define MY_DEBUG_VERBOSE + +//#define MY_BAUD_RATE 57600 + +#define MY_NODE_ID 123 +#define GATEWAY_ID 0 + +// Enable and select radio type attached +#define MY_RADIO_NRF24 +//#define MY_RADIO_RFM69 + +// defines for sensors +//#define BATTERYLEVEL 0 +#define SMSTEXT 1 + + +// Enable repeater functionality for this node +//#define MY_REPEATER_FEATURE + + +// All includes +#include +#include +#include +#include + +// Pin definitions and other defines +#define FONA_RX 2 +#define FONA_TX 3 +#define FONA_RST 4 + +#define defaultledpin 8 // usually this is pin 13, but better to use another digital pin + +// constants + +#define MAXSMSLENGTH 30 // No need for longer messages from GSM's as V_TEXT is limiting what can be sent to the other nodes. Node addresses are maximum 000 -> 255 +#define MAXMSGLENGTH 25 // limiting factor is the payload of V_TEXT, which is 25 chars. Nodes will never send you more then this in 1 message. +#define MAXNUMBERLENGTH 12 // based on "plus" sign, a country prefix and national number. Example in Belgium: +32 123 45 67 +#define MAXNODEID 254 // highest value a node ID can have + +// following strings need to be set by you, maximum length is 30 CHARS. +#define MYPASSWORD "Password" // replace this with your preferred passphrase to gain ownership +#define CONFIRMOWNER "I am yours" // replace this string if your partner is of the untrusting type ;-) +#define MYRELEASEWORD "I release you" // replace this with your preferred release confirmation + +// variables + +boolean KnowMyOwner = false; +boolean MsgReceived = false; +uint16_t smslen = 0; +int8_t smsnum = 0; +int bufferindex = 0; + +char smsbuffer[MAXSMSLENGTH + 1] = ""; +char msgbuffer[MAXMSGLENGTH + 1] = ""; +char nodemsgbuffer[MAXMSGLENGTH + 1] = ""; +char nodeaddress[5]; +char Numbers[11] = "0123456789"; + +char myOwnersNumber[MAXNUMBERLENGTH + 1] = ""; +char ReceivedNumber[MAXNUMBERLENGTH + 1] = ""; + +// Instantiate objects +MyMessage SMSMsg(SMSTEXT, V_TEXT); +Adafruit_FONA fona = Adafruit_FONA(FONA_RST); +SoftwareSerial fonaSS = SoftwareSerial(FONA_TX, FONA_RX); +SoftwareSerial *fonaSerial = &fonaSS; + + + + + + + +///////////////////////////////////////////////////////////////////////// +// supporting functions. +///////////////////////////////////////////////////////////////////////// +void blipled() +{ + digitalWrite(defaultledpin, HIGH); // turn the LED on (HIGH is the voltage level) + wait(3); // wait for a second + digitalWrite(defaultledpin, LOW); // turn the LED off by making the voltage HIGH + wait(100); // wait for a second + digitalWrite(defaultledpin, HIGH); // turn the LED on (HIGH is the voltage level) + wait(3); // wait for a second + digitalWrite(defaultledpin, LOW); // turn the LED off by making the voltage HIGH +} + + + +///////////////////////////////////////////////////////////////////////// +int GetNodeID() +{ + int TheAddress = -1; + TheAddress = ((smsbuffer[1] - 48) * 100) + ((smsbuffer[2] - 48) * 10) + (smsbuffer[3] - 48); + return TheAddress; +} + + + +///////////////////////////////////////////////////////////////////////// +bool IsAddressingNode() +{ + if (strlen(smsbuffer) > 5) + { // at least something to check + if ((smsbuffer[0] == 'N') && (smsbuffer[4] == ':') && (strchr(Numbers, smsbuffer[1]) != NULL) && (strchr(Numbers, smsbuffer[2]) != NULL) && (strchr(Numbers, smsbuffer[3]) != NULL)) + { +#ifdef MY_DEBUG + Serial.print("Message addressed to: "); + Serial.println(GetNodeID()); +#endif + if (GetNodeID() <= MAXNODEID) + return true; + else + return false; + } + else + { + return false; + } + } + else + { + return false; + } +} + + +///////////////////////////////////////////////////////////////////////// +char* GetMessageContent(char incomingsmsbuffer[MAXSMSLENGTH]) +{ + strcpy(nodemsgbuffer, ""); + for (int i = 5; i < MAXSMSLENGTH; i++) + { + nodemsgbuffer[i - 5] = incomingsmsbuffer[i]; + } + return nodemsgbuffer; +} + + +///////////////////////////////////////////////////////////////////////// +void presentation() +{ + // Send the sketch version information to the gateway and Controller + sendSketchInfo(SKETCHNAME, SKETCHVERSION); + wait(500); + // node ID is 123 + present(SMSTEXT, S_INFO); + wait(500); +} + + + + +///////////////////////////////////////////////////////////////////////// +void receive(const MyMessage & message) +{ +#ifdef MY_DEBUG + Serial.print(F("Incoming from sensor: ")); + Serial.print(message.sensor); +#endif + + + + if ((message.type == V_TEXT) and (!MsgReceived)) + { + sprintf(smsbuffer, "N%d:", message.sender); + strcat(smsbuffer, message.getString()); + strcpy(msgbuffer, message.getString()); + MsgReceived = true; + +#ifdef MY_DEBUG + Serial.print(F(", New text: ")); + Serial.print(message.getString()); +#endif + // send a copy of the received message to the controller + } + +#ifdef MY_DEBUG + Serial.println(); +#endif + +} // end: void receive() + + + +///////////////////////////////////////////////////////////////////////// +void clearSMSmemory() +{ + int8_t smsnum = fona.getNumSMS(); + while (smsnum > 0) + { + fona.deleteSMS(smsnum); + smsnum--; + } +} + + + +///////////////////////////////////////////////////////////////////////// +// the setup function runs once when you press reset or power the board +///////////////////////////////////////////////////////////////////////// +void setup() +{ + KnowMyOwner = false; + MsgReceived = false; + SMSMsg.setDestination(GATEWAY_ID); + + // initialize digital LEDpin as an output. + pinMode(defaultledpin, OUTPUT); + digitalWrite(defaultledpin, HIGH); // turn the LED on by making the voltage HIGH + +#ifdef MY_DEBUG + + Serial.println(F("SIM800L basic test")); + Serial.println(F("Initializing....(May take 3 seconds)")); + Serial.println(F("starting SIM800L")); + +#endif + + fonaSerial->begin(4800); + if (! fona.begin(*fonaSerial)) + { +#ifdef MY_DEBUG + Serial.println(F("Couldn't find SIM800L")); +#endif + while (1); + } + +#ifdef MY_DEBUG + Serial.println(F("SIM800L is OK")); +#endif + + digitalWrite(defaultledpin, LOW); // turn the LED off by making the voltage LOW + wait(250); // wait for a bit + digitalWrite(defaultledpin, HIGH); // turn the LED on by making the voltage HIGH + +#ifdef MY_DEBUG + // Print SIM card IMEI number. + char imei[15] = {0}; // MUST use a 16 character buffer for IMEI! + uint8_t imeiLen = fona.getIMEI(imei); + if (imeiLen > 0) { + Serial.print(F("SIM card IMEI: ")); Serial.println(imei); + } +#endif + + smsnum = fona.getNumSMS(); + + if (smsnum < 0) + { +#ifdef MY_DEBUG + Serial.println(F("Could not read # SMS")); +#endif + } + else + { +#ifdef MY_DEBUG + Serial.print(smsnum); + Serial.println(F(" SMS's on SIM card!")); +#endif + } + + clearSMSmemory(); + + smsnum = fona.getNumSMS(); + + if (smsnum == 0) + { +#ifdef MY_DEBUG + Serial.println(F("SMS Memory cleared")); +#endif + } + + digitalWrite(defaultledpin, LOW); // turn the LED off by making the voltage LOW + +} + +/////////////////////////////////////////////////////// +// the loop function runs over and over again forever +/////////////////////////////////////////////////////// +void loop() +{ + blipled(); + // sensor.request(SMSTEXT, V_TEXT, 0); + + wait(500); // wait for a second and proces messages + +#ifdef MY_DEBUG + Serial.print(F("Owner's number: ")); + Serial.println(myOwnersNumber); + Serial.print(F("Last received number: ")); + Serial.println(ReceivedNumber); +#endif + + smsnum = fona.getNumSMS(); + + if (smsnum < 0) + { +#ifdef MY_DEBUG + Serial.println(F("Could not read # SMS")); +#endif + } + +#ifdef MY_DEBUG + Serial.println(F("Process incoming messages")); +#endif + + if (MsgReceived && KnowMyOwner) + { + // a node sent us V_TEXT and we know the owner, so we can send an SMS + + SMSMsg.setDestination(GATEWAY_ID); + send(SMSMsg.set(smsbuffer)); + + if (fona.sendSMS(myOwnersNumber, smsbuffer)) + { + // SMS was sent to owner + MsgReceived = false; + strcpy(smsbuffer, ""); + strcpy(msgbuffer, ""); + } + else + { + // We do not know the owner, then ignore this message, we know the owner but no message was received, so just to be safe: + MsgReceived = false; + strcpy(msgbuffer, ""); + } + } + + + if (smsnum > 0) + { // we received an SMS and now need to check it + +#ifdef MY_DEBUG + Serial.print(smsnum); + Serial.println(F(" SMS received")); +#endif + + if (! fona.readSMS(smsnum, smsbuffer, MAXSMSLENGTH, &smslen)) + { // could not read SMS + +#ifdef MY_DEBUG + Serial.println(F("Failed to get SMS!")); +#endif + + } + else + { // We could read the SMS, now retreive sms to smsbuffer and number of origin + fona.getSMSSender(smsnum, ReceivedNumber, MAXNUMBERLENGTH); + +#ifdef MY_DEBUG + Serial.print(F("***** SMS #")); Serial.print(smsnum); + Serial.print(F(" (")); Serial.print(smslen); Serial.println(F(") bytes *****")); + Serial.println(smsbuffer); + Serial.print(F("from: ")); + Serial.println(ReceivedNumber); + Serial.println(F("***************************")); + Serial.print(F("Owner is known: ")); + if (KnowMyOwner) + Serial.println(F("yes")); + else + Serial.println(F("no")); + Serial.println(); +#endif + + if (!KnowMyOwner) + { // no owner, so check request for ownership + if (strcmp(smsbuffer, MYPASSWORD) == 0) + { // valid question for ownership + strcpy(smsbuffer, "OwnReq by: "); + strcat(smsbuffer, ReceivedNumber); + send(SMSMsg.set(smsbuffer)); + KnowMyOwner = true; + strcpy(myOwnersNumber, ReceivedNumber); + // from now on we can respond to owner + +#ifdef MY_DEBUG + Serial.print(F("Request for ownership by ")); + Serial.println(myOwnersNumber); +#endif + + strcpy(smsbuffer, CONFIRMOWNER); + if (fona.sendSMS(myOwnersNumber, smsbuffer)) + { // send confirmation to new owner + strcpy(smsbuffer, "Owner is informed."); + SMSMsg.setDestination(GATEWAY_ID); + send(SMSMsg.set(smsbuffer)); + +#ifdef MY_DEBUG + Serial.print(smsbuffer); + Serial.print(": "); + Serial.println(myOwnersNumber); +#endif + } + else + { // could not send confirmation to new owner + + strcpy(smsbuffer, "Owner is not informed."); + SMSMsg.setDestination(GATEWAY_ID); + send(SMSMsg.set(smsbuffer)); + + } + + + + strcpy(smsbuffer, ""); + } + else + { // no owner and no valid request, so ignore and log in controller + strcpy(smsbuffer, "Attempt by: "); + strcat(smsbuffer, ReceivedNumber); + SMSMsg.setDestination(GATEWAY_ID); + send(SMSMsg.set(smsbuffer)); + strcpy(smsbuffer, ""); + } + + } + + + if (KnowMyOwner) + { // now we can accept SMS messages but we need to check the origin of the SMS + + if (strcmp(myOwnersNumber, ReceivedNumber) == 0) + { // this is the owner talking, so handle his SMS + +#ifdef MY_DEBUG + Serial.println(); + Serial.print(F("Owner is talking: ")); + Serial.println(smsbuffer); + Serial.println(); +#endif + + if (strcmp(smsbuffer, MYRELEASEWORD) == 0) + { + + strcpy(smsbuffer, "Released by "); + strcat(smsbuffer, ReceivedNumber); + SMSMsg.setDestination(GATEWAY_ID); + send(SMSMsg.set(smsbuffer)); + + strcpy(smsbuffer, "I am released."); + if (fona.sendSMS(myOwnersNumber, smsbuffer)) + { + strcpy(smsbuffer, "Owner is informed."); + SMSMsg.setDestination(GATEWAY_ID); + send(SMSMsg.set(smsbuffer)); + } + else + { + strcpy(smsbuffer, "Owner is not informed."); + SMSMsg.setDestination(GATEWAY_ID); + send(SMSMsg.set(smsbuffer)); + } + + // clean up buffers, we are done and need to get ready for new owner request, ignore further messages + KnowMyOwner = false; + MsgReceived = false; + strcpy(myOwnersNumber, ""); + strcpy(ReceivedNumber, ""); + strcpy(smsbuffer, ""); + strcpy(msgbuffer, ""); + } + + + if (strcmp(smsbuffer, "Blip") == 0) + { // handle the command to light the defaultled. This could be anything else of course + + digitalWrite(defaultledpin, HIGH); // turn the LED on (HIGH is the voltage level) + wait(2000); // wait for two seconds + digitalWrite(defaultledpin, LOW); // turn the LED off by making the voltage LOW + + strcpy(smsbuffer, "R: Blip"); + SMSMsg.setDestination(GATEWAY_ID); + send(SMSMsg.set(smsbuffer)); + strcpy(smsbuffer, ""); + } + + + // and here we put the code to pass the message on to another node + // smsbuffer contains the first 30 characters of the SMS received. + // if a message starts with Nxxx:1234567890123456789012345 then you need to pass on the content to node Nxxx + // the node needs to be able to handle the incoming V_TEXT message + + if (IsAddressingNode()) // check if sms is in Node addressing format + { + int NodeID = GetNodeID(); + +#ifdef MY_DEBUG + + Serial.println(); + Serial.print("Message for node "); + Serial.print(NodeID); + Serial.print(" is treated: "); + Serial.println(GetMessageContent(smsbuffer)); + Serial.println(); + +#endif + +// send a copy of the incoming message to the controller + SMSMsg.setDestination(GATEWAY_ID); + send(SMSMsg.set(smsbuffer)); +// send the stripped message to the addressed node + SMSMsg.setDestination(NodeID); + SMSMsg.set(GetMessageContent(smsbuffer)); + send(SMSMsg); + + strcpy(smsbuffer, ""); + } + + + + + + // finally we mention to the controller all the SMS messages we received and did not treat. + + if (strcmp(smsbuffer, "") != 0) + { // so we still got something to do +#ifdef MY_DEBUG + Serial.println(smsbuffer); + Serial.println(); +#endif + //strcpy(smsbuffer, "Received crap from owner."); + SMSMsg.setDestination(GATEWAY_ID); + send(SMSMsg.set(smsbuffer)); + strcpy(smsbuffer, ""); + } + + } + else + { // not the owner trying to get access + strcpy(smsbuffer, "Hack by:"); + strcat(smsbuffer, ReceivedNumber); + SMSMsg.setDestination(GATEWAY_ID); + send(SMSMsg.set(smsbuffer)); +#ifdef MY_DEBUG + Serial.print(F("Hijack attempt by: ")); + Serial.println(ReceivedNumber); +#else + if (fona.sendSMS(myOwnersNumber, smsbuffer)) + { + strcpy(smsbuffer, "Owner is informed."); + SMSMsg.setDestination(GATEWAY_ID); + send(SMSMsg.set(smsbuffer)); + } + else + { + strcpy(smsbuffer, "Owner could not be informed."); + SMSMsg.setDestination(GATEWAY_ID); + send(SMSMsg.set(smsbuffer)); + } +#endif + } + + } + + } + + clearSMSmemory(); + + } + +} + + + + + + +