├── .travis.yml ├── Adafruit_FONA.cpp ├── Adafruit_FONA.h ├── README.md ├── examples ├── FONAtest │ └── FONAtest.ino ├── GPS │ └── GPS.ino └── IncomingCall │ └── IncomingCall.ino └── library.properties /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | before_install: 3 | - "/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_1.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :1 -ac -screen 0 1280x1024x16" 4 | - sleep 3 5 | - export DISPLAY=:1.0 6 | - wget http://downloads.arduino.cc/arduino-1.6.5-linux64.tar.xz 7 | - tar xf arduino-1.6.5-linux64.tar.xz 8 | - sudo mv arduino-1.6.5 /usr/local/share/arduino 9 | - sudo ln -s /usr/local/share/arduino/arduino /usr/local/bin/arduino 10 | install: 11 | - ln -s $PWD /usr/local/share/arduino/libraries/Adafruit_FONA 12 | - arduino --install-boards arduino:sam > /dev/null 13 | script: 14 | - arduino --board arduino:avr:uno --save-prefs 15 | - arduino --verify $PWD/examples/FONAtest/FONAtest.ino 16 | - arduino --verify $PWD/examples/IncomingCall/IncomingCall.ino 17 | - arduino --verify $PWD/examples/GPS/GPS.ino 18 | - arduino --board arduino:sam:arduino_due_x --save-prefs 19 | - arduino --verify $PWD/examples/FONAtest/FONAtest.ino 20 | - arduino --verify $PWD/examples/IncomingCall/IncomingCall.ino 21 | - arduino --verify $PWD/examples/GPS/GPS.ino 22 | notifications: 23 | email: 24 | on_success: change 25 | on_failure: change 26 | -------------------------------------------------------------------------------- /Adafruit_FONA.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************** 2 | This is a library for our Adafruit FONA Cellular Module 3 | 4 | Designed specifically to work with the Adafruit FONA 5 | ----> http://www.adafruit.com/products/1946 6 | ----> http://www.adafruit.com/products/1963 7 | 8 | These displays use TTL Serial to communicate, 2 pins are required to 9 | interface 10 | Adafruit invests time and resources providing this open source code, 11 | please support Adafruit and open-source hardware by purchasing 12 | products from Adafruit! 13 | 14 | Written by Limor Fried/Ladyada for Adafruit Industries. 15 | BSD license, all text above must be included in any redistribution 16 | ****************************************************/ 17 | #include 18 | // next line per http://postwarrior.com/arduino-ethershield-error-prog_char-does-not-name-a-type/ 19 | #define prog_char char PROGMEM 20 | 21 | #if (ARDUINO >= 100) 22 | #include "Arduino.h" 23 | #ifndef __SAM3X8E__ // Arduino Due doesn't support SoftwareSerial 24 | #include 25 | #endif 26 | #else 27 | #include "WProgram.h" 28 | #include 29 | #endif 30 | 31 | #include "Adafruit_FONA.h" 32 | 33 | Adafruit_FONA::Adafruit_FONA(int8_t rst) 34 | { 35 | _rstpin = rst; 36 | 37 | apn = F("FONAnet"); 38 | apnusername = 0; 39 | apnpassword = 0; 40 | mySerial = 0; 41 | httpsredirect = false; 42 | useragent = F("FONA"); 43 | } 44 | 45 | boolean Adafruit_FONA::begin(Stream &port) { 46 | mySerial = &port; 47 | 48 | pinMode(_rstpin, OUTPUT); 49 | digitalWrite(_rstpin, HIGH); 50 | delay(10); 51 | digitalWrite(_rstpin, LOW); 52 | delay(100); 53 | digitalWrite(_rstpin, HIGH); 54 | 55 | // give 3 seconds to reboot 56 | delay(3000); 57 | 58 | while (mySerial->available()) mySerial->read(); 59 | 60 | sendCheckReply(F("AT"), F("OK")); 61 | delay(100); 62 | sendCheckReply(F("AT"), F("OK")); 63 | delay(100); 64 | sendCheckReply(F("AT"), F("OK")); 65 | delay(100); 66 | 67 | // turn off Echo! 68 | sendCheckReply(F("ATE0"), F("OK")); 69 | delay(100); 70 | 71 | if (! sendCheckReply(F("ATE0"), F("OK"))) { 72 | return false; 73 | } 74 | 75 | return true; 76 | } 77 | 78 | 79 | /********* Real Time Clock ********************************************/ 80 | 81 | boolean Adafruit_FONA::readRTC(uint8_t *year, uint8_t *month, uint8_t *date, uint8_t *hr, uint8_t *min, uint8_t *sec) { 82 | uint16_t v; 83 | sendParseReply(F("AT+CCLK?"), F("+CCLK: "), &v, '/', 0); 84 | *year = v; 85 | 86 | Serial.println(*year); 87 | } 88 | 89 | boolean Adafruit_FONA::enableRTC(uint8_t i) { 90 | if (! sendCheckReply(F("AT+CLTS="), i, F("OK"))) 91 | return false; 92 | return sendCheckReply(F("AT&W"), F("OK")); 93 | } 94 | 95 | 96 | /********* BATTERY & ADC ********************************************/ 97 | 98 | /* returns value in mV (uint16_t) */ 99 | boolean Adafruit_FONA::getBattVoltage(uint16_t *v) { 100 | return sendParseReply(F("AT+CBC"), F("+CBC: "), v, ',', 2); 101 | } 102 | 103 | /* returns the percentage charge of battery as reported by sim800 */ 104 | boolean Adafruit_FONA::getBattPercent(uint16_t *p) { 105 | return sendParseReply(F("AT+CBC"), F("+CBC: "), p, ',', 1); 106 | } 107 | 108 | boolean Adafruit_FONA::getADCVoltage(uint16_t *v) { 109 | return sendParseReply(F("AT+CADC?"), F("+CADC: 1,"), v); 110 | } 111 | 112 | /********* SIM ***********************************************************/ 113 | 114 | uint8_t Adafruit_FONA::unlockSIM(char *pin) 115 | { 116 | char sendbuff[14] = "AT+CPIN="; 117 | sendbuff[8] = pin[0]; 118 | sendbuff[9] = pin[1]; 119 | sendbuff[10] = pin[2]; 120 | sendbuff[11] = pin[3]; 121 | sendbuff[12] = NULL; 122 | 123 | return sendCheckReply(sendbuff, "OK"); 124 | } 125 | 126 | uint8_t Adafruit_FONA::getSIMCCID(char *ccid) { 127 | getReply("AT+CCID"); 128 | // up to 20 chars 129 | strncpy(ccid, replybuffer, 20); 130 | ccid[20] = 0; 131 | 132 | readline(); // eat 'OK' 133 | 134 | return strlen(ccid); 135 | } 136 | 137 | /********* IMEI **********************************************************/ 138 | 139 | uint8_t Adafruit_FONA::getIMEI(char *imei) { 140 | getReply("AT+GSN"); 141 | 142 | // up to 15 chars 143 | strncpy(imei, replybuffer, 15); 144 | imei[15] = 0; 145 | 146 | readline(); // eat 'OK' 147 | 148 | return strlen(imei); 149 | } 150 | 151 | /********* NETWORK *******************************************************/ 152 | 153 | uint8_t Adafruit_FONA::getNetworkStatus(void) { 154 | uint16_t status; 155 | 156 | if (! sendParseReply(F("AT+CREG?"), F("+CREG: "), &status, ',', 1)) return 0; 157 | 158 | return status; 159 | } 160 | 161 | 162 | uint8_t Adafruit_FONA::getRSSI(void) { 163 | uint16_t reply; 164 | 165 | if (! sendParseReply(F("AT+CSQ"), F("+CSQ: "), &reply) ) return 0; 166 | 167 | return reply; 168 | } 169 | 170 | /********* AUDIO *******************************************************/ 171 | 172 | boolean Adafruit_FONA::setAudio(uint8_t a) { 173 | // 0 is headset, 1 is external audio 174 | if (a > 1) return false; 175 | 176 | return sendCheckReply(F("AT+CHFA="), a, F("OK")); 177 | } 178 | 179 | uint8_t Adafruit_FONA::getVolume(void) { 180 | uint16_t reply; 181 | 182 | if (! sendParseReply(F("AT+CLVL?"), F("+CLVL: "), &reply) ) return 0; 183 | 184 | return reply; 185 | } 186 | 187 | boolean Adafruit_FONA::setVolume(uint8_t i) { 188 | return sendCheckReply(F("AT+CLVL="), i, F("OK")); 189 | } 190 | 191 | 192 | boolean Adafruit_FONA::playDTMF(char dtmf) { 193 | char str[4]; 194 | str[0] = '\"'; 195 | str[1] = dtmf; 196 | str[2] = '\"'; 197 | str[3] = 0; 198 | return sendCheckReply(F("AT+CLDTMF=3,"), str, F("OK")); 199 | } 200 | 201 | boolean Adafruit_FONA::playToolkitTone(uint8_t t, uint16_t len) { 202 | return sendCheckReply(F("AT+STTONE=1,"), t, len, F("OK")); 203 | } 204 | 205 | boolean Adafruit_FONA::setMicVolume(uint8_t a, uint8_t level) { 206 | // 0 is headset, 1 is external audio 207 | if (a > 1) return false; 208 | 209 | return sendCheckReply(F("AT+CMIC="), a, level, F("OK")); 210 | } 211 | 212 | /********* FM RADIO *******************************************************/ 213 | 214 | 215 | boolean Adafruit_FONA::FMradio(boolean onoff, uint8_t a) { 216 | if (! onoff) { 217 | return sendCheckReply(F("AT+FMCLOSE"), F("OK")); 218 | } 219 | 220 | // 0 is headset, 1 is external audio 221 | if (a > 1) return false; 222 | 223 | return sendCheckReply(F("AT+FMOPEN="), a, F("OK")); 224 | } 225 | 226 | boolean Adafruit_FONA::tuneFMradio(uint16_t station) { 227 | // Fail if FM station is outside allowed range. 228 | if ((station < 870) || (station > 1090)) 229 | return false; 230 | 231 | return sendCheckReply(F("AT+FMFREQ="), station, F("OK")); 232 | } 233 | 234 | boolean Adafruit_FONA::setFMVolume(uint8_t i) { 235 | // Fail if volume is outside allowed range (0-6). 236 | if (i > 6) { 237 | return false; 238 | } 239 | // Send FM volume command and verify response. 240 | return sendCheckReply(F("AT+FMVOLUME="), i, F("OK")); 241 | } 242 | 243 | int8_t Adafruit_FONA::getFMVolume() { 244 | uint16_t level; 245 | 246 | if (! sendParseReply(F("AT+FMVOLUME?"), F("+FMVOLUME: "), &level) ) return 0; 247 | 248 | return level; 249 | } 250 | 251 | int8_t Adafruit_FONA::getFMSignalLevel(uint16_t station) { 252 | // Fail if FM station is outside allowed range. 253 | if ((station < 875) || (station > 1080)) { 254 | return -1; 255 | } 256 | 257 | // Send FM signal level query command. 258 | // Note, need to explicitly send timeout so right overload is chosen. 259 | getReply(F("AT+FMSIGNAL="), station, FONA_DEFAULT_TIMEOUT_MS); 260 | // Check response starts with expected value. 261 | char *p = strstr_P(replybuffer, PSTR("+FMSIGNAL: ")); 262 | if (p == 0) return -1; 263 | p+=11; 264 | // Find second colon to get start of signal quality. 265 | p = strchr(p, ':'); 266 | if (p == 0) return -1; 267 | p+=1; 268 | // Parse signal quality. 269 | int8_t level = atoi(p); 270 | readline(); // eat the "OK" 271 | return level; 272 | } 273 | 274 | /********* PWM/BUZZER **************************************************/ 275 | 276 | boolean Adafruit_FONA::setPWM(uint16_t period, uint8_t duty) { 277 | if (period > 2000) return false; 278 | if (duty > 100) return false; 279 | 280 | return sendCheckReply(F("AT+SPWM=0,"), period, duty, F("OK")); 281 | } 282 | 283 | /********* CALL PHONES **************************************************/ 284 | boolean Adafruit_FONA::callPhone(char *number) { 285 | char sendbuff[35] = "ATD"; 286 | strncpy(sendbuff+3, number, min(30, strlen(number))); 287 | uint8_t x = strlen(sendbuff); 288 | sendbuff[x] = ';'; 289 | sendbuff[x+1] = 0; 290 | //Serial.println(sendbuff); 291 | 292 | return sendCheckReply(sendbuff, "OK"); 293 | } 294 | 295 | boolean Adafruit_FONA::hangUp(void) { 296 | return sendCheckReply(F("ATH0"), F("OK")); 297 | } 298 | 299 | boolean Adafruit_FONA::pickUp(void) { 300 | return sendCheckReply(F("ATA"), F("OK")); 301 | } 302 | 303 | void Adafruit_FONA::onIncomingCall() { 304 | #ifdef ADAFRUIT_FONA_DEBUG 305 | Serial.print(F("> ")); Serial.println(F("Incoming call...")); 306 | #endif 307 | Adafruit_FONA::_incomingCall = true; 308 | } 309 | 310 | boolean Adafruit_FONA::_incomingCall = false; 311 | 312 | boolean Adafruit_FONA::callerIdNotification(boolean enable, uint8_t interrupt) { 313 | if(enable){ 314 | attachInterrupt(interrupt, onIncomingCall, FALLING); 315 | return sendCheckReply(F("AT+CLIP=1"), F("OK")); 316 | } 317 | 318 | detachInterrupt(interrupt); 319 | return sendCheckReply(F("AT+CLIP=0"), F("OK")); 320 | } 321 | 322 | boolean Adafruit_FONA::incomingCallNumber(char* phonenum) { 323 | //+CLIP: "",145,"",0,"",0 324 | if(!Adafruit_FONA::_incomingCall) 325 | return false; 326 | 327 | readline(); 328 | while(!strcmp_P(replybuffer, (prog_char*)F("RING")) == 0) { 329 | flushInput(); 330 | readline(); 331 | } 332 | 333 | readline(); //reads incoming phone number line 334 | 335 | parseReply(F("+CLIP: \""), phonenum, '"'); 336 | 337 | #ifdef ADAFRUIT_FONA_DEBUG 338 | Serial.print(F("Phone Number: ")); 339 | Serial.println(replybuffer); 340 | #endif 341 | 342 | Adafruit_FONA::_incomingCall = false; 343 | return true; 344 | } 345 | 346 | /********* SMS **********************************************************/ 347 | 348 | uint8_t Adafruit_FONA::getSMSInterrupt(void) { 349 | uint16_t reply; 350 | 351 | if (! sendParseReply(F("AT+CFGRI?"), F("+CFGRI: "), &reply) ) return 0; 352 | 353 | return reply; 354 | } 355 | 356 | boolean Adafruit_FONA::setSMSInterrupt(uint8_t i) { 357 | return sendCheckReply(F("AT+CFGRI="), i, F("OK")); 358 | } 359 | 360 | int8_t Adafruit_FONA::getNumSMS(void) { 361 | uint16_t numsms; 362 | 363 | if (! sendCheckReply(F("AT+CMGF=1"), F("OK"))) return -1; 364 | // ask how many sms are stored 365 | 366 | if (! sendParseReply(F("AT+CPMS?"), F("+CPMS: \"SM_P\","), &numsms) ) return -1; 367 | 368 | return numsms; 369 | } 370 | 371 | // Reading SMS's is a bit involved so we don't use helpers that may cause delays or debug 372 | // printouts! 373 | boolean Adafruit_FONA::readSMS(uint8_t i, char *smsbuff, 374 | uint16_t maxlen, uint16_t *readlen) { 375 | // text mode 376 | if (! sendCheckReply(F("AT+CMGF=1"), F("OK"))) return false; 377 | 378 | // show all text mode parameters 379 | if (! sendCheckReply(F("AT+CSDH=1"), F("OK"))) return false; 380 | 381 | // parse out the SMS len 382 | uint16_t thesmslen = 0; 383 | 384 | //getReply(F("AT+CMGR="), i, 1000); // do not print debug! 385 | mySerial->print(F("AT+CMGR=")); 386 | mySerial->println(i); 387 | readline(1000); // timeout 388 | 389 | //Serial.print(F("Reply: ")); Serial.println(replybuffer); 390 | // parse it out... 391 | if (! parseReply(F("+CMGR:"), &thesmslen, ',', 11)) { 392 | *readlen = 0; 393 | return false; 394 | } 395 | 396 | readRaw(thesmslen); 397 | 398 | flushInput(); 399 | 400 | uint16_t thelen = min(maxlen, strlen(replybuffer)); 401 | strncpy(smsbuff, replybuffer, thelen); 402 | smsbuff[thelen] = 0; // end the string 403 | 404 | #ifdef ADAFRUIT_FONA_DEBUG 405 | Serial.println(replybuffer); 406 | #endif 407 | *readlen = thelen; 408 | return true; 409 | } 410 | 411 | // Retrieve the sender of the specified SMS message and copy it as a string to 412 | // the sender buffer. Up to senderlen characters of the sender will be copied 413 | // and a null terminator will be added if less than senderlen charactesr are 414 | // copied to the result. Returns true if a result was successfully retrieved, 415 | // otherwise false. 416 | boolean Adafruit_FONA::getSMSSender(uint8_t i, char *sender, int senderlen) { 417 | // Ensure text mode and all text mode parameters are sent. 418 | if (! sendCheckReply(F("AT+CMGF=1"), F("OK"))) return false; 419 | if (! sendCheckReply(F("AT+CSDH=1"), F("OK"))) return false; 420 | // Send command to retrieve SMS message and parse a line of response. 421 | mySerial->print(F("AT+CMGR=")); 422 | mySerial->println(i); 423 | readline(1000); 424 | // Parse the second field in the response. 425 | boolean result = parseReplyQuoted(F("+CMGR:"), sender, senderlen, ',', 1); 426 | // Drop any remaining data from the response. 427 | flushInput(); 428 | return result; 429 | } 430 | 431 | boolean Adafruit_FONA::sendSMS(char *smsaddr, char *smsmsg) { 432 | if (! sendCheckReply("AT+CMGF=1", "OK")) return -1; 433 | 434 | char sendcmd[30] = "AT+CMGS=\""; 435 | strncpy(sendcmd+9, smsaddr, 30-9-2); // 9 bytes beginning, 2 bytes for close quote + null 436 | sendcmd[strlen(sendcmd)] = '\"'; 437 | 438 | if (! sendCheckReply(sendcmd, "> ")) return false; 439 | #ifdef ADAFRUIT_FONA_DEBUG 440 | Serial.print(F("> ")); Serial.println(smsmsg); 441 | #endif 442 | mySerial->println(smsmsg); 443 | mySerial->println(); 444 | mySerial->write(0x1A); 445 | #ifdef ADAFRUIT_FONA_DEBUG 446 | Serial.println("^Z"); 447 | #endif 448 | readline(10000); // read the +CMGS reply, wait up to 10 seconds!!! 449 | //Serial.print("* "); Serial.println(replybuffer); 450 | if (strstr(replybuffer, "+CMGS") == 0) { 451 | return false; 452 | } 453 | readline(1000); // read OK 454 | //Serial.print("* "); Serial.println(replybuffer); 455 | 456 | if (strcmp(replybuffer, "OK") != 0) { 457 | return false; 458 | } 459 | 460 | return true; 461 | } 462 | 463 | 464 | boolean Adafruit_FONA::deleteSMS(uint8_t i) { 465 | if (! sendCheckReply("AT+CMGF=1", "OK")) return -1; 466 | // read an sms 467 | char sendbuff[12] = "AT+CMGD=000"; 468 | sendbuff[8] = (i / 100) + '0'; 469 | i %= 100; 470 | sendbuff[9] = (i / 10) + '0'; 471 | i %= 10; 472 | sendbuff[10] = i + '0'; 473 | 474 | return sendCheckReply(sendbuff, "OK", 2000); 475 | } 476 | 477 | /********* TIME **********************************************************/ 478 | 479 | boolean Adafruit_FONA::enableNetworkTimeSync(boolean onoff) { 480 | if (onoff) { 481 | if (! sendCheckReply(F("AT+CLTS=1"), F("OK"))) 482 | return false; 483 | } else { 484 | if (! sendCheckReply(F("AT+CLTS=0"), F("OK"))) 485 | return false; 486 | } 487 | 488 | flushInput(); // eat any 'Unsolicted Result Code' 489 | 490 | return true; 491 | } 492 | 493 | boolean Adafruit_FONA::enableNTPTimeSync(boolean onoff, const __FlashStringHelper *ntpserver) { 494 | if (onoff) { 495 | if (! sendCheckReply(F("AT+CNTPCID=1"), F("OK"))) 496 | return false; 497 | 498 | mySerial->print(F("AT+CNTP=\"")); 499 | if (ntpserver != 0) { 500 | mySerial->print(ntpserver); 501 | } else { 502 | mySerial->print(F("pool.ntp.org")); 503 | } 504 | mySerial->println(F("\",0")); 505 | readline(FONA_DEFAULT_TIMEOUT_MS); 506 | if (strcmp(replybuffer, "OK") != 0) 507 | return false; 508 | 509 | if (! sendCheckReply(F("AT+CNTP"), F("OK"), 10000)) 510 | return false; 511 | 512 | uint16_t status; 513 | readline(10000); 514 | if (! parseReply(F("+CNTP:"), &status)) 515 | return false; 516 | } else { 517 | if (! sendCheckReply(F("AT+CNTPCID=0"), F("OK"))) 518 | return false; 519 | } 520 | 521 | return true; 522 | } 523 | 524 | boolean Adafruit_FONA::getTime(char *buff, uint16_t maxlen) { 525 | getReply(F("AT+CCLK?"), (uint16_t) 10000); 526 | if (strncmp(replybuffer, "+CCLK: ", 7) != 0) 527 | return false; 528 | 529 | char *p = replybuffer+7; 530 | uint16_t lentocopy = min(maxlen-1, strlen(p)); 531 | strncpy(buff, p, lentocopy+1); 532 | buff[lentocopy] = 0; 533 | 534 | readline(); // eat OK 535 | 536 | return true; 537 | } 538 | 539 | /********* GPS **********************************************************/ 540 | 541 | 542 | boolean Adafruit_FONA::enableGPS(boolean onoff) { 543 | uint16_t state; 544 | 545 | // first check if its already on or off 546 | if (! sendParseReply(F("AT+CGPSPWR?"), F("+CGPSPWR: "), &state) ) 547 | return false; 548 | 549 | if (onoff && !state) { 550 | if (! sendCheckReply(F("AT+CGPSPWR=1"), F("OK"))) 551 | return false; 552 | } else if (!onoff && state) { 553 | if (! sendCheckReply(F("AT+CGPSPWR=0"), F("OK"))) 554 | return false; 555 | } 556 | return true; 557 | } 558 | 559 | int8_t Adafruit_FONA::GPSstatus(void) { 560 | uint16_t state; 561 | 562 | getReply(F("AT+CGPSSTATUS?")); 563 | 564 | char *p = strstr_P(replybuffer, (prog_char*)F("+CGPSSTATUS: Location ")); 565 | if (p == 0) return -1; 566 | 567 | p+=22; 568 | //Serial.println(p); 569 | 570 | readline(); // eat 'OK' 571 | 572 | 573 | if (p[0] == 'U') return 0; 574 | if (p[0] == 'N') return 1; 575 | if (p[0] == '2') return 2; 576 | if (p[0] == '3') return 3; 577 | 578 | // else 579 | return 0; 580 | } 581 | 582 | uint8_t Adafruit_FONA::getGPS(uint8_t arg, char *buffer, uint8_t maxbuff) { 583 | int32_t x = arg; 584 | 585 | getReply(F("AT+CGPSINF="), x); 586 | 587 | char *p = strstr_P(replybuffer, (prog_char*)F("CGPSINF: ")); 588 | if (p == 0){ 589 | buffer[0] = 0; 590 | return 0; 591 | } 592 | p+=9; 593 | uint8_t len = max(maxbuff-1, strlen(p)); 594 | strncpy(buffer, p, len); 595 | buffer[len] = 0; 596 | 597 | readline(); // eat 'OK' 598 | return len; 599 | } 600 | 601 | boolean Adafruit_FONA::getGPS(float *lat, float *lon, float *speed_kph, float *heading, float *altitude) { 602 | 603 | char gpsbuffer[120]; 604 | 605 | // we need at least a 2D fix 606 | if (GPSstatus() < 2) 607 | return false; 608 | 609 | // grab the mode 2^5 gps csv from the sim808 610 | uint8_t res_len = getGPS(32, gpsbuffer, 120); 611 | 612 | // make sure we have a response 613 | if (res_len == 0) 614 | return false; 615 | 616 | // skip mode 617 | char *tok = strtok(gpsbuffer, ","); 618 | if (! tok) return false; 619 | 620 | // skip date 621 | tok = strtok(NULL, ","); 622 | if (! tok) return false; 623 | 624 | // skip fix 625 | tok = strtok(NULL, ","); 626 | if (! tok) return false; 627 | 628 | // grab the latitude 629 | char *latp = strtok(NULL, ","); 630 | if (! latp) return false; 631 | 632 | // grab latitude direction 633 | char *latdir = strtok(NULL, ","); 634 | if (! latdir) return false; 635 | 636 | // grab longitude 637 | char *longp = strtok(NULL, ","); 638 | if (! longp) return false; 639 | 640 | // grab longitude direction 641 | char *longdir = strtok(NULL, ","); 642 | if (! longdir) return false; 643 | 644 | double latitude = atof(latp); 645 | double longitude = atof(longp); 646 | 647 | // convert latitude from minutes to decimal 648 | float degrees = floor(latitude / 100); 649 | double minutes = latitude - (100 * degrees); 650 | minutes /= 60; 651 | degrees += minutes; 652 | 653 | // turn direction into + or - 654 | if (latdir[0] == 'S') degrees *= -1; 655 | 656 | *lat = degrees; 657 | 658 | // convert longitude from minutes to decimal 659 | degrees = floor(longitude / 100); 660 | minutes = longitude - (100 * degrees); 661 | minutes /= 60; 662 | degrees += minutes; 663 | 664 | // turn direction into + or - 665 | if (longdir[0] == 'W') degrees *= -1; 666 | 667 | *lon = degrees; 668 | 669 | // only grab speed if needed 670 | if (speed_kph != NULL) { 671 | 672 | // grab the speed in knots 673 | char *speedp = strtok(NULL, ","); 674 | if (! speedp) return false; 675 | 676 | // convert to kph 677 | *speed_kph = atof(speedp) * 1.852; 678 | 679 | } 680 | 681 | // only grab heading if needed 682 | if (heading != NULL) { 683 | 684 | // grab the speed in knots 685 | char *coursep = strtok(NULL, ","); 686 | if (! coursep) return false; 687 | 688 | *heading = atof(coursep); 689 | 690 | } 691 | 692 | // no need to continue 693 | if (altitude == NULL) 694 | return true; 695 | 696 | // we need at least a 3D fix for altitude 697 | if (GPSstatus() < 3) 698 | return false; 699 | 700 | // grab the mode 0 gps csv from the sim808 701 | res_len = getGPS(0, gpsbuffer, 120); 702 | 703 | // make sure we have a response 704 | if (res_len == 0) 705 | return false; 706 | 707 | // skip mode 708 | tok = strtok(gpsbuffer, ","); 709 | if (! tok) return false; 710 | 711 | // skip lat 712 | tok = strtok(NULL, ","); 713 | if (! tok) return false; 714 | 715 | // skip long 716 | tok = strtok(NULL, ","); 717 | if (! tok) return false; 718 | 719 | // grab altitude 720 | char *altp = strtok(NULL, ","); 721 | if (! altp) return false; 722 | 723 | *altitude = atof(altp); 724 | 725 | return true; 726 | 727 | } 728 | 729 | boolean Adafruit_FONA::enableGPSNMEA(uint8_t i) { 730 | 731 | char sendbuff[15] = "AT+CGPSOUT=000"; 732 | sendbuff[11] = (i / 100) + '0'; 733 | i %= 100; 734 | sendbuff[12] = (i / 10) + '0'; 735 | i %= 10; 736 | sendbuff[13] = i + '0'; 737 | 738 | return sendCheckReply(sendbuff, "OK", 2000); 739 | } 740 | 741 | 742 | /********* GPRS **********************************************************/ 743 | 744 | 745 | boolean Adafruit_FONA::enableGPRS(boolean onoff) { 746 | 747 | if (onoff) { 748 | // disconnect all sockets 749 | sendCheckReply(F("AT+CIPSHUT"), F("SHUT OK"), 5000); 750 | 751 | if (! sendCheckReply(F("AT+CGATT=1"), F("OK"), 10000)) 752 | return false; 753 | 754 | // set bearer profile! connection type GPRS 755 | if (! sendCheckReply(F("AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\""), 756 | F("OK"), 10000)) 757 | return false; 758 | 759 | // set bearer profile access point name 760 | if (apn) { 761 | // Send command AT+SAPBR=3,1,"APN","" where is the configured APN value. 762 | if (! sendCheckReplyQuoted(F("AT+SAPBR=3,1,\"APN\","), apn, F("OK"), 10000)) 763 | return false; 764 | 765 | // set username/password 766 | if (apnusername) { 767 | // Send command AT+SAPBR=3,1,"USER","" where is the configured APN username. 768 | if (! sendCheckReplyQuoted(F("AT+SAPBR=3,1,\"USER\","), apnusername, F("OK"), 10000)) 769 | return false; 770 | } 771 | if (apnpassword) { 772 | // Send command AT+SAPBR=3,1,"PWD","" where is the configured APN password. 773 | if (! sendCheckReplyQuoted(F("AT+SAPBR=3,1,\"PWD\","), apnpassword, F("OK"), 10000)) 774 | return false; 775 | } 776 | } 777 | 778 | // open GPRS context 779 | if (! sendCheckReply(F("AT+SAPBR=1,1"), F("OK"), 10000)) 780 | return false; 781 | } else { 782 | // disconnect all sockets 783 | if (! sendCheckReply(F("AT+CIPSHUT"), F("SHUT OK"), 5000)) 784 | return false; 785 | 786 | // close GPRS context 787 | if (! sendCheckReply(F("AT+SAPBR=0,1"), F("OK"), 10000)) 788 | return false; 789 | 790 | if (! sendCheckReply(F("AT+CGATT=0"), F("OK"), 10000)) 791 | return false; 792 | 793 | } 794 | return true; 795 | } 796 | 797 | uint8_t Adafruit_FONA::GPRSstate(void) { 798 | uint16_t state; 799 | 800 | if (! sendParseReply(F("AT+CGATT?"), F("+CGATT: "), &state) ) 801 | return -1; 802 | 803 | return state; 804 | } 805 | 806 | void Adafruit_FONA::setGPRSNetworkSettings(const __FlashStringHelper *apn, 807 | const __FlashStringHelper *username, const __FlashStringHelper *password) { 808 | this->apn = apn; 809 | this->apnusername = username; 810 | this->apnpassword = password; 811 | } 812 | 813 | boolean Adafruit_FONA::getGSMLoc(uint16_t *errorcode, char *buff, uint16_t maxlen) { 814 | 815 | getReply(F("AT+CIPGSMLOC=1,1"), (uint16_t)10000); 816 | 817 | if (! parseReply(F("+CIPGSMLOC: "), errorcode)) 818 | return false; 819 | 820 | char *p = replybuffer+14; 821 | uint16_t lentocopy = min(maxlen-1, strlen(p)); 822 | strncpy(buff, p, lentocopy+1); 823 | 824 | readline(); // eat OK 825 | 826 | return true; 827 | } 828 | 829 | boolean Adafruit_FONA::getGSMLoc(float *lat, float *lon) { 830 | 831 | uint16_t returncode; 832 | char gpsbuffer[120]; 833 | 834 | // make sure we could get a response 835 | if (! getGSMLoc(&returncode, gpsbuffer, 120)) 836 | return false; 837 | 838 | // make sure we have a valid return code 839 | if (returncode != 0) 840 | return false; 841 | 842 | // tokenize the gps buffer to locate the lat & long 843 | char *latp = strtok(gpsbuffer, ","); 844 | if (! latp) return false; 845 | 846 | char *longp = strtok(NULL, ","); 847 | if (! longp) return false; 848 | 849 | *lat = atof(latp); 850 | *lon = atof(longp); 851 | 852 | return true; 853 | 854 | } 855 | /********* TCP FUNCTIONS ************************************/ 856 | 857 | 858 | boolean Adafruit_FONA::TCPconnect(char *server, uint16_t port) { 859 | flushInput(); 860 | 861 | // close all old connections 862 | if (! sendCheckReply(F("AT+CIPSHUT"), F("SHUT OK"), 5000) ) return false; 863 | 864 | // single connection at a time 865 | if (! sendCheckReply(F("AT+CIPMUX=0"), F("OK")) ) return false; 866 | 867 | // manually read data 868 | if (! sendCheckReply(F("AT+CIPRXGET=1"), F("OK")) ) return false; 869 | 870 | #ifdef ADAFRUIT_FONA_DEBUG 871 | Serial.print(F("AT+CIPSTART=\"TCP\",\"")); 872 | Serial.print(server); 873 | Serial.print(F("\",\"")); 874 | Serial.print(port); 875 | Serial.println(F("\"")); 876 | #endif 877 | 878 | mySerial->print(F("AT+CIPSTART=\"TCP\",\"")); 879 | mySerial->print(server); 880 | mySerial->print(F("\",\"")); 881 | mySerial->print(port); 882 | mySerial->println(F("\"")); 883 | 884 | if (! expectReply(F("OK"))) return false; 885 | if (! expectReply(F("CONNECT OK"))) return false; 886 | } 887 | 888 | boolean Adafruit_FONA::TCPclose(void) { 889 | return sendCheckReply(F("AT+CIPCLOSE"), F("OK")); 890 | } 891 | 892 | boolean Adafruit_FONA::TCPconnected(void) { 893 | if (! sendCheckReply(F("AT+CIPSTATUS"), F("OK"), 100) ) return false; 894 | readline(100); 895 | #ifdef ADAFRUIT_FONA_DEBUG 896 | Serial.print (F("\t<--- ")); Serial.println(replybuffer); 897 | #endif 898 | return (strcmp(replybuffer, "STATE: CONNECT OK") == 0); 899 | } 900 | 901 | boolean Adafruit_FONA::TCPsend(char *packet, uint8_t len) { 902 | 903 | #ifdef ADAFRUIT_FONA_DEBUG 904 | Serial.print(F("AT+CIPSEND=")); 905 | Serial.println(len); 906 | 907 | for (uint16_t i=0; iprint(F("AT+CIPSEND=")); 916 | mySerial->println(len); 917 | readline(); 918 | #ifdef ADAFRUIT_FONA_DEBUG 919 | Serial.print (F("\t<--- ")); Serial.println(replybuffer); 920 | #endif 921 | if (replybuffer[0] != '>') return false; 922 | 923 | mySerial->write(packet, len); 924 | readline(3000); // wait up to 3 seconds to send the data 925 | #ifdef ADAFRUIT_FONA_DEBUG 926 | Serial.print (F("\t<--- ")); Serial.println(replybuffer); 927 | #endif 928 | 929 | return (strcmp(replybuffer, "SEND OK") == 0); 930 | } 931 | 932 | uint16_t Adafruit_FONA::TCPavailable(void) { 933 | uint16_t avail; 934 | 935 | if (! sendParseReply(F("AT+CIPRXGET=4"), F("+CIPRXGET: 4,"), &avail, ',', 0) ) return false; 936 | 937 | #ifdef ADAFRUIT_FONA_DEBUG 938 | Serial.print (avail); Serial.println(F(" bytes available")); 939 | #endif 940 | 941 | return avail; 942 | } 943 | 944 | 945 | uint16_t Adafruit_FONA::TCPread(uint8_t *buff, uint8_t len) { 946 | uint16_t avail; 947 | 948 | mySerial->print(F("AT+CIPRXGET=2,")); 949 | mySerial->println(len); 950 | readline(); 951 | if (! parseReply(F("+CIPRXGET: 2,"), &avail, ',', 0)) return false; 952 | 953 | readRaw(avail); 954 | 955 | #ifdef ADAFRUIT_FONA_DEBUG 956 | Serial.print (avail); Serial.println(F(" bytes read")); 957 | for (uint8_t i=0;i "); 986 | Serial.print(F("AT+HTTPPARA=\"")); 987 | Serial.print(parameter); 988 | Serial.println('"'); 989 | #endif 990 | 991 | mySerial->print(F("AT+HTTPPARA=\"")); 992 | mySerial->print(parameter); 993 | if (quoted) 994 | mySerial->print(F("\",\"")); 995 | else 996 | mySerial->print(F("\",")); 997 | } 998 | 999 | boolean Adafruit_FONA::HTTP_para_end(boolean quoted) { 1000 | if (quoted) 1001 | mySerial->println('"'); 1002 | else 1003 | mySerial->println(); 1004 | 1005 | return expectReply(F("OK")); 1006 | } 1007 | 1008 | boolean Adafruit_FONA::HTTP_para(const __FlashStringHelper *parameter, 1009 | const char *value) { 1010 | HTTP_para_start(parameter, true); 1011 | mySerial->print(value); 1012 | return HTTP_para_end(true); 1013 | } 1014 | 1015 | boolean Adafruit_FONA::HTTP_para(const __FlashStringHelper *parameter, 1016 | const __FlashStringHelper *value) { 1017 | HTTP_para_start(parameter, true); 1018 | mySerial->print(value); 1019 | return HTTP_para_end(true); 1020 | } 1021 | 1022 | boolean Adafruit_FONA::HTTP_para(const __FlashStringHelper *parameter, 1023 | int32_t value) { 1024 | HTTP_para_start(parameter, false); 1025 | mySerial->print(value); 1026 | return HTTP_para_end(false); 1027 | } 1028 | 1029 | boolean Adafruit_FONA::HTTP_data(uint32_t size, uint32_t maxTime) { 1030 | flushInput(); 1031 | 1032 | #ifdef ADAFRUIT_FONA_DEBUG 1033 | Serial.print("\t---> "); 1034 | Serial.print(F("AT+HTTPDATA=")); 1035 | Serial.print(size); 1036 | Serial.print(","); 1037 | Serial.println(maxTime); 1038 | #endif 1039 | 1040 | mySerial->print(F("AT+HTTPDATA=")); 1041 | mySerial->print(size); 1042 | mySerial->print(","); 1043 | mySerial->println(maxTime); 1044 | 1045 | return expectReply(F("DOWNLOAD")); 1046 | } 1047 | 1048 | boolean Adafruit_FONA::HTTP_action(uint8_t method, uint16_t *status, 1049 | uint16_t *datalen, int32_t timeout) { 1050 | // Send request. 1051 | if (! sendCheckReply(F("AT+HTTPACTION="), method, F("OK"))) 1052 | return false; 1053 | 1054 | // Parse response status and size. 1055 | readline(timeout); 1056 | if (! parseReply(F("+HTTPACTION:"), status, ',', 1)) 1057 | return false; 1058 | if (! parseReply(F("+HTTPACTION:"), datalen, ',', 2)) 1059 | return false; 1060 | 1061 | return true; 1062 | } 1063 | 1064 | boolean Adafruit_FONA::HTTP_readall(uint16_t *datalen) { 1065 | getReply(F("AT+HTTPREAD")); 1066 | if (! parseReply(F("+HTTPREAD:"), datalen, ',', 0)) 1067 | return false; 1068 | 1069 | return true; 1070 | } 1071 | 1072 | boolean Adafruit_FONA::HTTP_ssl(boolean onoff) { 1073 | return sendCheckReply(F("AT+HTTPSSL="), onoff ? 1 : 0, F("OK")); 1074 | } 1075 | 1076 | /********* HTTP HIGH LEVEL FUNCTIONS ***************************/ 1077 | 1078 | boolean Adafruit_FONA::HTTP_GET_start(char *url, 1079 | uint16_t *status, uint16_t *datalen){ 1080 | if (! HTTP_setup(url)) 1081 | return false; 1082 | 1083 | // HTTP GET 1084 | if (! HTTP_action(FONA_HTTP_GET, status, datalen)) 1085 | return false; 1086 | 1087 | Serial.print("Status: "); Serial.println(*status); 1088 | Serial.print("Len: "); Serial.println(*datalen); 1089 | 1090 | // HTTP response data 1091 | if (! HTTP_readall(datalen)) 1092 | return false; 1093 | 1094 | return true; 1095 | } 1096 | 1097 | void Adafruit_FONA::HTTP_GET_end(void) { 1098 | HTTP_term(); 1099 | } 1100 | 1101 | boolean Adafruit_FONA::HTTP_POST_start(char *url, 1102 | const __FlashStringHelper *contenttype, 1103 | const uint8_t *postdata, uint16_t postdatalen, 1104 | uint16_t *status, uint16_t *datalen){ 1105 | if (! HTTP_setup(url)) 1106 | return false; 1107 | 1108 | if (! HTTP_para(F("CONTENT"), contenttype)) { 1109 | return false; 1110 | } 1111 | 1112 | // HTTP POST data 1113 | if (! HTTP_data(postdatalen, 10000)) 1114 | return false; 1115 | mySerial->write(postdata, postdatalen); 1116 | if (! expectReply(F("OK"))) 1117 | return false; 1118 | 1119 | // HTTP POST 1120 | if (! HTTP_action(FONA_HTTP_POST, status, datalen)) 1121 | return false; 1122 | 1123 | Serial.print("Status: "); Serial.println(*status); 1124 | Serial.print("Len: "); Serial.println(*datalen); 1125 | 1126 | // HTTP response data 1127 | if (! HTTP_readall(datalen)) 1128 | return false; 1129 | 1130 | return true; 1131 | } 1132 | 1133 | void Adafruit_FONA::HTTP_POST_end(void) { 1134 | HTTP_term(); 1135 | } 1136 | 1137 | void Adafruit_FONA::setUserAgent(const __FlashStringHelper *useragent) { 1138 | this->useragent = useragent; 1139 | } 1140 | 1141 | void Adafruit_FONA::setHTTPSRedirect(boolean onoff) { 1142 | httpsredirect = onoff; 1143 | } 1144 | 1145 | /********* HTTP HELPERS ****************************************/ 1146 | 1147 | boolean Adafruit_FONA::HTTP_setup(char *url) { 1148 | // Handle any pending 1149 | HTTP_term(); 1150 | 1151 | // Initialize and set parameters 1152 | if (! HTTP_init()) 1153 | return false; 1154 | if (! HTTP_para(F("CID"), 1)) 1155 | return false; 1156 | if (! HTTP_para(F("UA"), useragent)) 1157 | return false; 1158 | if (! HTTP_para(F("URL"), url)) 1159 | return false; 1160 | 1161 | // HTTPS redirect 1162 | if (httpsredirect) { 1163 | if (! HTTP_para(F("REDIR"),1)) 1164 | return false; 1165 | 1166 | if (! HTTP_ssl(true)) 1167 | return false; 1168 | } 1169 | 1170 | return true; 1171 | } 1172 | 1173 | /********* HELPERS *********************************************/ 1174 | 1175 | boolean Adafruit_FONA::expectReply(const __FlashStringHelper *reply, 1176 | uint16_t timeout) { 1177 | readline(timeout); 1178 | #ifdef ADAFRUIT_FONA_DEBUG 1179 | Serial.print(F("\t<--- ")); Serial.println(replybuffer); 1180 | #endif 1181 | return (strcmp_P(replybuffer, (prog_char*)reply) == 0); 1182 | } 1183 | 1184 | /********* LOW LEVEL *******************************************/ 1185 | 1186 | inline int Adafruit_FONA::available(void) { 1187 | return mySerial->available(); 1188 | } 1189 | 1190 | inline size_t Adafruit_FONA::write(uint8_t x) { 1191 | return mySerial->write(x); 1192 | } 1193 | 1194 | inline int Adafruit_FONA::read(void) { 1195 | return mySerial->read(); 1196 | } 1197 | 1198 | inline int Adafruit_FONA::peek(void) { 1199 | return mySerial->peek(); 1200 | } 1201 | 1202 | inline void Adafruit_FONA::flush() { 1203 | mySerial->flush(); 1204 | } 1205 | 1206 | void Adafruit_FONA::flushInput() { 1207 | // Read all available serial input to flush pending data. 1208 | uint16_t timeoutloop = 0; 1209 | while (timeoutloop++ < 40) { 1210 | while(available()) { 1211 | read(); 1212 | timeoutloop = 0; // If char was received reset the timer 1213 | } 1214 | delay(1); 1215 | } 1216 | } 1217 | 1218 | uint16_t Adafruit_FONA::readRaw(uint16_t b) { 1219 | uint16_t idx = 0; 1220 | 1221 | while (b && (idx < sizeof(replybuffer)-1)) { 1222 | if (mySerial->available()) { 1223 | replybuffer[idx] = mySerial->read(); 1224 | idx++; 1225 | b--; 1226 | } 1227 | } 1228 | replybuffer[idx] = 0; 1229 | 1230 | return idx; 1231 | } 1232 | 1233 | uint8_t Adafruit_FONA::readline(uint16_t timeout, boolean multiline) { 1234 | uint16_t replyidx = 0; 1235 | 1236 | while (timeout--) { 1237 | if (replyidx >= 254) { 1238 | //Serial.println(F("SPACE")); 1239 | break; 1240 | } 1241 | 1242 | while(mySerial->available()) { 1243 | char c = mySerial->read(); 1244 | if (c == '\r') continue; 1245 | if (c == 0xA) { 1246 | if (replyidx == 0) // the first 0x0A is ignored 1247 | continue; 1248 | 1249 | if (!multiline) { 1250 | timeout = 0; // the second 0x0A is the end of the line 1251 | break; 1252 | } 1253 | } 1254 | replybuffer[replyidx] = c; 1255 | //Serial.print(c, HEX); Serial.print("#"); Serial.println(c); 1256 | replyidx++; 1257 | } 1258 | 1259 | if (timeout == 0) { 1260 | //Serial.println(F("TIMEOUT")); 1261 | break; 1262 | } 1263 | delay(1); 1264 | } 1265 | replybuffer[replyidx] = 0; // null term 1266 | return replyidx; 1267 | } 1268 | 1269 | uint8_t Adafruit_FONA::getReply(char *send, uint16_t timeout) { 1270 | flushInput(); 1271 | 1272 | #ifdef ADAFRUIT_FONA_DEBUG 1273 | Serial.print("\t---> "); Serial.println(send); 1274 | #endif 1275 | 1276 | mySerial->println(send); 1277 | 1278 | uint8_t l = readline(timeout); 1279 | #ifdef ADAFRUIT_FONA_DEBUG 1280 | Serial.print (F("\t<--- ")); Serial.println(replybuffer); 1281 | #endif 1282 | return l; 1283 | } 1284 | 1285 | uint8_t Adafruit_FONA::getReply(const __FlashStringHelper *send, uint16_t timeout) { 1286 | flushInput(); 1287 | 1288 | #ifdef ADAFRUIT_FONA_DEBUG 1289 | Serial.print("\t---> "); Serial.println(send); 1290 | #endif 1291 | 1292 | mySerial->println(send); 1293 | 1294 | uint8_t l = readline(timeout); 1295 | #ifdef ADAFRUIT_FONA_DEBUG 1296 | Serial.print (F("\t<--- ")); Serial.println(replybuffer); 1297 | #endif 1298 | return l; 1299 | } 1300 | 1301 | // Send prefix, suffix, and newline. Return response (and also set replybuffer with response). 1302 | uint8_t Adafruit_FONA::getReply(const __FlashStringHelper *prefix, char *suffix, uint16_t timeout) { 1303 | flushInput(); 1304 | 1305 | #ifdef ADAFRUIT_FONA_DEBUG 1306 | Serial.print("\t---> "); Serial.print(prefix); Serial.println(suffix); 1307 | #endif 1308 | 1309 | mySerial->print(prefix); 1310 | mySerial->println(suffix); 1311 | 1312 | uint8_t l = readline(timeout); 1313 | #ifdef ADAFRUIT_FONA_DEBUG 1314 | Serial.print (F("\t<--- ")); Serial.println(replybuffer); 1315 | #endif 1316 | return l; 1317 | } 1318 | 1319 | // Send prefix, suffix, and newline. Return response (and also set replybuffer with response). 1320 | uint8_t Adafruit_FONA::getReply(const __FlashStringHelper *prefix, int32_t suffix, uint16_t timeout) { 1321 | flushInput(); 1322 | 1323 | #ifdef ADAFRUIT_FONA_DEBUG 1324 | Serial.print("\t---> "); Serial.print(prefix); Serial.println(suffix, DEC); 1325 | #endif 1326 | 1327 | mySerial->print(prefix); 1328 | mySerial->println(suffix, DEC); 1329 | 1330 | uint8_t l = readline(timeout); 1331 | #ifdef ADAFRUIT_FONA_DEBUG 1332 | Serial.print (F("\t<--- ")); Serial.println(replybuffer); 1333 | #endif 1334 | return l; 1335 | } 1336 | 1337 | // Send prefix, suffix, suffix2, and newline. Return response (and also set replybuffer with response). 1338 | uint8_t Adafruit_FONA::getReply(const __FlashStringHelper *prefix, int32_t suffix1, int32_t suffix2, uint16_t timeout) { 1339 | flushInput(); 1340 | 1341 | #ifdef ADAFRUIT_FONA_DEBUG 1342 | Serial.print("\t---> "); Serial.print(prefix); 1343 | Serial.print(suffix1, DEC); Serial.print(","); Serial.println(suffix2, DEC); 1344 | #endif 1345 | 1346 | mySerial->print(prefix); 1347 | mySerial->print(suffix1); 1348 | mySerial->print(','); 1349 | mySerial->println(suffix2, DEC); 1350 | 1351 | uint8_t l = readline(timeout); 1352 | #ifdef ADAFRUIT_FONA_DEBUG 1353 | Serial.print (F("\t<--- ")); Serial.println(replybuffer); 1354 | #endif 1355 | return l; 1356 | } 1357 | 1358 | // Send prefix, ", suffix, ", and newline. Return response (and also set replybuffer with response). 1359 | uint8_t Adafruit_FONA::getReplyQuoted(const __FlashStringHelper *prefix, const __FlashStringHelper *suffix, uint16_t timeout) { 1360 | flushInput(); 1361 | 1362 | #ifdef ADAFRUIT_FONA_DEBUG 1363 | Serial.print("\t---> "); Serial.print(prefix); 1364 | Serial.print('"'); Serial.print(suffix); Serial.println('"'); 1365 | #endif 1366 | 1367 | mySerial->print(prefix); 1368 | mySerial->print('"'); 1369 | mySerial->print(suffix); 1370 | mySerial->println('"'); 1371 | 1372 | uint8_t l = readline(timeout); 1373 | #ifdef ADAFRUIT_FONA_DEBUG 1374 | Serial.print (F("\t<--- ")); Serial.println(replybuffer); 1375 | #endif 1376 | return l; 1377 | } 1378 | 1379 | boolean Adafruit_FONA::sendCheckReply(char *send, char *reply, uint16_t timeout) { 1380 | getReply(send, timeout); 1381 | 1382 | /* 1383 | for (uint8_t i=0; i http://www.adafruit.com/products/1946 6 | ----> http://www.adafruit.com/products/1963 7 | 8 | These displays use TTL Serial to communicate, 2 pins are required to 9 | interface 10 | Adafruit invests time and resources providing this open source code, 11 | please support Adafruit and open-source hardware by purchasing 12 | products from Adafruit! 13 | 14 | Written by Limor Fried/Ladyada for Adafruit Industries. 15 | BSD license, all text above must be included in any redistribution 16 | ****************************************************/ 17 | #ifndef ADAFRUIT_FONA_H 18 | #define ADAFRUIT_FONA_H 19 | 20 | #if (ARDUINO >= 100) 21 | #include "Arduino.h" 22 | #ifndef __SAM3X8E__ // Arduino Due doesn't support SoftwareSerial 23 | #include 24 | #endif 25 | #else 26 | #include "WProgram.h" 27 | #include 28 | #endif 29 | 30 | //#define ADAFRUIT_FONA_DEBUG 31 | 32 | #define FONA_HEADSETAUDIO 0 33 | #define FONA_EXTAUDIO 1 34 | 35 | #define FONA_STTONE_DIALTONE 1 36 | #define FONA_STTONE_BUSY 2 37 | #define FONA_STTONE_CONGESTION 3 38 | #define FONA_STTONE_PATHACK 4 39 | #define FONA_STTONE_DROPPED 5 40 | #define FONA_STTONE_ERROR 6 41 | #define FONA_STTONE_CALLWAIT 7 42 | #define FONA_STTONE_RINGING 8 43 | #define FONA_STTONE_BEEP 16 44 | #define FONA_STTONE_POSTONE 17 45 | #define FONA_STTONE_ERRTONE 18 46 | #define FONA_STTONE_INDIANDIALTONE 19 47 | #define FONA_STTONE_USADIALTONE 20 48 | 49 | #define FONA_DEFAULT_TIMEOUT_MS 500 50 | 51 | #define FONA_HTTP_GET 0 52 | #define FONA_HTTP_POST 1 53 | #define FONA_HTTP_HEAD 2 54 | 55 | class Adafruit_FONA : public Stream { 56 | public: 57 | Adafruit_FONA(int8_t r); 58 | boolean begin(Stream &port); 59 | 60 | // Stream 61 | int available(void); 62 | size_t write(uint8_t x); 63 | int read(void); 64 | int peek(void); 65 | void flush(); 66 | 67 | // RTC 68 | boolean enableRTC(uint8_t i); 69 | boolean readRTC(uint8_t *year, uint8_t *month, uint8_t *date, uint8_t *hr, uint8_t *min, uint8_t *sec); 70 | 71 | // Battery and ADC 72 | boolean getADCVoltage(uint16_t *v); 73 | boolean getBattPercent(uint16_t *p); 74 | boolean getBattVoltage(uint16_t *v); 75 | 76 | // SIM query 77 | uint8_t unlockSIM(char *pin); 78 | uint8_t getSIMCCID(char *ccid); 79 | uint8_t getNetworkStatus(void); 80 | uint8_t getRSSI(void); 81 | 82 | // IMEI 83 | uint8_t getIMEI(char *imei); 84 | 85 | // set Audio output 86 | boolean setAudio(uint8_t a); 87 | boolean setVolume(uint8_t i); 88 | uint8_t getVolume(void); 89 | boolean playToolkitTone(uint8_t t, uint16_t len); 90 | boolean setMicVolume(uint8_t a, uint8_t level); 91 | boolean playDTMF(char tone); 92 | 93 | // FM radio functions. 94 | boolean tuneFMradio(uint16_t station); 95 | boolean FMradio(boolean onoff, uint8_t a = FONA_HEADSETAUDIO); 96 | boolean setFMVolume(uint8_t i); 97 | int8_t getFMVolume(); 98 | int8_t getFMSignalLevel(uint16_t station); 99 | 100 | // SMS handling 101 | boolean setSMSInterrupt(uint8_t i); 102 | uint8_t getSMSInterrupt(void); 103 | int8_t getNumSMS(void); 104 | boolean readSMS(uint8_t i, char *smsbuff, uint16_t max, uint16_t *readsize); 105 | boolean sendSMS(char *smsaddr, char *smsmsg); 106 | boolean deleteSMS(uint8_t i); 107 | boolean getSMSSender(uint8_t i, char *sender, int senderlen); 108 | 109 | // Time 110 | boolean enableNetworkTimeSync(boolean onoff); 111 | boolean enableNTPTimeSync(boolean onoff, const __FlashStringHelper *ntpserver=0); 112 | boolean getTime(char *buff, uint16_t maxlen); 113 | 114 | // GPRS handling 115 | boolean enableGPRS(boolean onoff); 116 | uint8_t GPRSstate(void); 117 | boolean getGSMLoc(uint16_t *replycode, char *buff, uint16_t maxlen); 118 | boolean getGSMLoc(float *lat, float *lon); 119 | void setGPRSNetworkSettings(const __FlashStringHelper *apn, const __FlashStringHelper *username=0, const __FlashStringHelper *password=0); 120 | 121 | // GPS handling 122 | boolean enableGPS(boolean onoff); 123 | int8_t GPSstatus(void); 124 | uint8_t getGPS(uint8_t arg, char *buffer, uint8_t maxbuff); 125 | boolean getGPS(float *lat, float *lon, float *speed_kph=0, float *heading=0, float *altitude=0); 126 | boolean enableGPSNMEA(uint8_t nmea); 127 | 128 | // TCP raw connections 129 | boolean TCPconnect(char *server, uint16_t port); 130 | boolean TCPclose(void); 131 | boolean TCPconnected(void); 132 | boolean TCPsend(char *packet, uint8_t len); 133 | uint16_t TCPavailable(void); 134 | uint16_t TCPread(uint8_t *buff, uint8_t len); 135 | 136 | // HTTP low level interface (maps directly to SIM800 commands). 137 | boolean HTTP_init(); 138 | boolean HTTP_term(); 139 | void HTTP_para_start(const __FlashStringHelper *parameter, boolean quoted = true); 140 | boolean HTTP_para_end(boolean quoted = true); 141 | boolean HTTP_para(const __FlashStringHelper *parameter, const char *value); 142 | boolean HTTP_para(const __FlashStringHelper *parameter, const __FlashStringHelper *value); 143 | boolean HTTP_para(const __FlashStringHelper *parameter, int32_t value); 144 | boolean HTTP_data(uint32_t size, uint32_t maxTime=10000); 145 | boolean HTTP_action(uint8_t method, uint16_t *status, uint16_t *datalen, int32_t timeout = 10000); 146 | boolean HTTP_readall(uint16_t *datalen); 147 | boolean HTTP_ssl(boolean onoff); 148 | 149 | // HTTP high level interface (easier to use, less flexible). 150 | boolean HTTP_GET_start(char *url, uint16_t *status, uint16_t *datalen); 151 | void HTTP_GET_end(void); 152 | boolean HTTP_POST_start(char *url, const __FlashStringHelper *contenttype, const uint8_t *postdata, uint16_t postdatalen, uint16_t *status, uint16_t *datalen); 153 | void HTTP_POST_end(void); 154 | void setUserAgent(const __FlashStringHelper *useragent); 155 | 156 | // HTTPS 157 | void setHTTPSRedirect(boolean onoff); 158 | 159 | // PWM (buzzer) 160 | boolean setPWM(uint16_t period, uint8_t duty = 50); 161 | 162 | // Phone calls 163 | boolean callPhone(char *phonenum); 164 | boolean hangUp(void); 165 | boolean pickUp(void); 166 | boolean callerIdNotification(boolean enable, uint8_t interrupt = 0); 167 | boolean incomingCallNumber(char* phonenum); 168 | 169 | // Helper functions to verify responses. 170 | boolean expectReply(const __FlashStringHelper *reply, uint16_t timeout = 10000); 171 | boolean sendCheckReply(char *send, char *reply, uint16_t timeout = FONA_DEFAULT_TIMEOUT_MS); 172 | boolean sendCheckReply(const __FlashStringHelper *send, const __FlashStringHelper *reply, uint16_t timeout = FONA_DEFAULT_TIMEOUT_MS); 173 | 174 | 175 | private: 176 | int8_t _rstpin; 177 | 178 | char replybuffer[255]; 179 | const __FlashStringHelper *apn; 180 | const __FlashStringHelper *apnusername; 181 | const __FlashStringHelper *apnpassword; 182 | boolean httpsredirect; 183 | const __FlashStringHelper *useragent; 184 | 185 | // HTTP helpers 186 | boolean HTTP_setup(char *url); 187 | 188 | void flushInput(); 189 | uint16_t readRaw(uint16_t b); 190 | uint8_t readline(uint16_t timeout = FONA_DEFAULT_TIMEOUT_MS, boolean multiline = false); 191 | uint8_t getReply(char *send, uint16_t timeout = FONA_DEFAULT_TIMEOUT_MS); 192 | uint8_t getReply(const __FlashStringHelper *send, uint16_t timeout = FONA_DEFAULT_TIMEOUT_MS); 193 | uint8_t getReply(const __FlashStringHelper *prefix, char *suffix, uint16_t timeout = FONA_DEFAULT_TIMEOUT_MS); 194 | uint8_t getReply(const __FlashStringHelper *prefix, int32_t suffix, uint16_t timeout = FONA_DEFAULT_TIMEOUT_MS); 195 | 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. 196 | uint8_t getReplyQuoted(const __FlashStringHelper *prefix, const __FlashStringHelper *suffix, uint16_t timeout = FONA_DEFAULT_TIMEOUT_MS); 197 | 198 | boolean sendCheckReply(const __FlashStringHelper *prefix, char *suffix, const __FlashStringHelper *reply, uint16_t timeout = FONA_DEFAULT_TIMEOUT_MS); 199 | boolean sendCheckReply(const __FlashStringHelper *prefix, int32_t suffix, const __FlashStringHelper *reply, uint16_t timeout = FONA_DEFAULT_TIMEOUT_MS); 200 | boolean sendCheckReply(const __FlashStringHelper *prefix, int32_t suffix, int32_t suffix2, const __FlashStringHelper *reply, uint16_t timeout = FONA_DEFAULT_TIMEOUT_MS); 201 | boolean sendCheckReplyQuoted(const __FlashStringHelper *prefix, const __FlashStringHelper *suffix, const __FlashStringHelper *reply, uint16_t timeout = FONA_DEFAULT_TIMEOUT_MS); 202 | 203 | 204 | boolean parseReply(const __FlashStringHelper *toreply, 205 | uint16_t *v, char divider = ',', uint8_t index=0); 206 | boolean parseReply(const __FlashStringHelper *toreply, 207 | char *v, char divider = ',', uint8_t index=0); 208 | boolean parseReplyQuoted(const __FlashStringHelper *toreply, 209 | char *v, int maxlen, char divider, uint8_t index); 210 | 211 | boolean sendParseReply(const __FlashStringHelper *tosend, 212 | const __FlashStringHelper *toreply, 213 | uint16_t *v, char divider = ',', uint8_t index=0); 214 | 215 | static boolean _incomingCall; 216 | static void onIncomingCall(); 217 | 218 | Stream *mySerial; 219 | }; 220 | 221 | #endif 222 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 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) 2 | 3 | **This library requires Arduino v1.0.6 or higher** 4 | 5 | This is a library for the Adafruit FONA Cellular GSM Breakouts etc 6 | 7 | Designed specifically to work with the Adafruit FONA Breakout 8 | * https://www.adafruit.com/products/1946 9 | * https://www.adafruit.com/products/1963 10 | * http://www.adafruit.com/products/2468 11 | * http://www.adafruit.com/products/2542 12 | 13 | These modules use TTL Serial to communicate, 2 pins are required to interface 14 | 15 | Adafruit invests time and resources providing this open source code, 16 | please support Adafruit and open-source hardware by purchasing 17 | products from Adafruit! 18 | 19 | Check out the links above for our tutorials and wiring diagrams 20 | 21 | Written by Limor Fried/Ladyada for Adafruit Industries. 22 | BSD license, all text above must be included in any redistribution 23 | With updates from Samy Kamkar 24 | 25 | To download. click the DOWNLOADS button in the top right corner, rename the uncompressed folder Adafruit_FONA 26 | Check that the Adafruit_FONA folder contains Adafruit_FONA.cpp and Adafruit_FONA.h 27 | 28 | Place the Adafruit_FONA library folder your *arduinosketchfolder*/libraries/ folder. 29 | You may need to create the libraries subfolder if its your first library. Restart the IDE. 30 | -------------------------------------------------------------------------------- /examples/FONAtest/FONAtest.ino: -------------------------------------------------------------------------------- 1 | /*************************************************** 2 | This is an example for our Adafruit FONA Cellular Module 3 | 4 | Designed specifically to work with the Adafruit FONA 5 | ----> http://www.adafruit.com/products/1946 6 | ----> http://www.adafruit.com/products/1963 7 | ----> http://www.adafruit.com/products/2468 8 | ----> http://www.adafruit.com/products/2542 9 | 10 | These cellular modules use TTL Serial to communicate, 2 pins are 11 | required to interface 12 | Adafruit invests time and resources providing this open source code, 13 | please support Adafruit and open-source hardware by purchasing 14 | products from Adafruit! 15 | 16 | Written by Limor Fried/Ladyada for Adafruit Industries. 17 | BSD license, all text above must be included in any redistribution 18 | ****************************************************/ 19 | 20 | /* 21 | THIS CODE IS STILL IN PROGRESS! 22 | 23 | Open up the serial console on the Arduino at 115200 baud to interact with FONA 24 | 25 | Note that if you need to set a GPRS APN, username, and password scroll down to 26 | the commented section below at the end of the setup() function. 27 | */ 28 | #include "Adafruit_FONA.h" 29 | 30 | #define FONA_RX 2 31 | #define FONA_TX 3 32 | #define FONA_RST 4 33 | 34 | // this is a large buffer for replies 35 | char replybuffer[255]; 36 | 37 | // This is to handle the absence of software serial on platforms 38 | // like the Arduino Due. Modify this code if you are using different 39 | // hardware serial port, or if you are using a non-avr platform 40 | // that supports software serial. 41 | #ifdef __AVR__ 42 | #include 43 | SoftwareSerial fonaSS = SoftwareSerial(FONA_TX, FONA_RX); 44 | SoftwareSerial *fonaSerial = &fonaSS; 45 | #else 46 | HardwareSerial *fonaSerial = &Serial1; 47 | #endif 48 | 49 | Adafruit_FONA fona = Adafruit_FONA(FONA_RST); 50 | 51 | uint8_t readline(char *buff, uint8_t maxbuff, uint16_t timeout = 0); 52 | 53 | void setup() { 54 | while (!Serial); 55 | 56 | Serial.begin(115200); 57 | Serial.println(F("FONA basic test")); 58 | Serial.println(F("Initializing....(May take 3 seconds)")); 59 | 60 | fonaSerial->begin(4800); 61 | if (! fona.begin(*fonaSerial)) { 62 | Serial.println(F("Couldn't find FONA")); 63 | while(1); 64 | } 65 | Serial.println(F("FONA is OK")); 66 | 67 | // Print SIM card IMEI number. 68 | char imei[15] = {0}; // MUST use a 16 character buffer for IMEI! 69 | uint8_t imeiLen = fona.getIMEI(imei); 70 | if (imeiLen > 0) { 71 | Serial.print("SIM card IMEI: "); Serial.println(imei); 72 | } 73 | 74 | // Optionally configure a GPRS APN, username, and password. 75 | // You might need to do this to access your network's GPRS/data 76 | // network. Contact your provider for the exact APN, username, 77 | // and password values. Username and password are optional and 78 | // can be removed, but APN is required. 79 | //fona.setGPRSNetworkSettings(F("your APN"), F("your username"), F("your password")); 80 | 81 | // Optionally configure HTTP gets to follow redirects over SSL. 82 | // Default is not to follow SSL redirects, however if you uncomment 83 | // the following line then redirects over SSL will be followed. 84 | //fona.setHTTPSRedirect(true); 85 | 86 | printMenu(); 87 | } 88 | 89 | void printMenu(void) { 90 | Serial.println(F("-------------------------------------")); 91 | Serial.println(F("[?] Print this menu")); 92 | Serial.println(F("[a] read the ADC (2.8V max)")); 93 | Serial.println(F("[b] read the Battery V and % charged")); 94 | Serial.println(F("[C] read the SIM CCID")); 95 | Serial.println(F("[U] Unlock SIM with PIN code")); 96 | Serial.println(F("[i] read RSSI")); 97 | Serial.println(F("[n] get Network status")); 98 | Serial.println(F("[v] set audio Volume")); 99 | Serial.println(F("[V] get Volume")); 100 | Serial.println(F("[H] set Headphone audio")); 101 | Serial.println(F("[e] set External audio")); 102 | Serial.println(F("[T] play audio Tone")); 103 | Serial.println(F("[P] PWM/Buzzer out")); 104 | 105 | // FM (SIM800 only) 106 | Serial.println(F("[f] tune FM radio")); 107 | Serial.println(F("[F] turn off FM")); 108 | Serial.println(F("[m] set FM volume")); 109 | Serial.println(F("[M] get FM volume")); 110 | Serial.println(F("[q] get FM station signal level")); 111 | 112 | // Phone 113 | Serial.println(F("[c] make phone Call")); 114 | Serial.println(F("[h] Hang up phone")); 115 | Serial.println(F("[p] Pick up phone")); 116 | 117 | // SMS 118 | Serial.println(F("[N] Number of SMSs")); 119 | Serial.println(F("[r] Read SMS #")); 120 | Serial.println(F("[R] Read All SMS")); 121 | Serial.println(F("[d] Delete SMS #")); 122 | Serial.println(F("[s] Send SMS")); 123 | 124 | // Time 125 | Serial.println(F("[y] Enable network time sync")); 126 | Serial.println(F("[Y] Enable NTP time sync (GPRS)")); 127 | Serial.println(F("[t] Get network time")); 128 | 129 | // GPRS 130 | Serial.println(F("[G] Enable GPRS")); 131 | Serial.println(F("[g] Disable GPRS")); 132 | Serial.println(F("[l] Query GSMLOC (GPRS)")); 133 | Serial.println(F("[w] Read webpage (GPRS)")); 134 | Serial.println(F("[W] Post to website (GPRS)")); 135 | 136 | // GPS 137 | Serial.println(F("[O] Turn GPS on (SIM808)")); 138 | Serial.println(F("[o] Turn GPS off (SIM808)")); 139 | Serial.println(F("[x] GPS fix status (SIM808)")); 140 | Serial.println(F("[L] Query GPS location (SIM808)")); 141 | Serial.println(F("[E] Raw NMEA out (SIM808)")); 142 | 143 | Serial.println(F("[S] create Serial passthru tunnel")); 144 | Serial.println(F("-------------------------------------")); 145 | Serial.println(F("")); 146 | 147 | } 148 | void loop() { 149 | Serial.print(F("FONA> ")); 150 | while (! Serial.available() ) { 151 | if (fona.available()) { 152 | Serial.write(fona.read()); 153 | } 154 | } 155 | 156 | char command = Serial.read(); 157 | Serial.println(command); 158 | 159 | 160 | switch (command) { 161 | case '?': { 162 | printMenu(); 163 | break; 164 | } 165 | 166 | case 'a': { 167 | // read the ADC 168 | uint16_t adc; 169 | if (! fona.getADCVoltage(&adc)) { 170 | Serial.println(F("Failed to read ADC")); 171 | } else { 172 | Serial.print(F("ADC = ")); Serial.print(adc); Serial.println(F(" mV")); 173 | } 174 | break; 175 | } 176 | 177 | case 'b': { 178 | // read the battery voltage and percentage 179 | uint16_t vbat; 180 | if (! fona.getBattVoltage(&vbat)) { 181 | Serial.println(F("Failed to read Batt")); 182 | } else { 183 | Serial.print(F("VBat = ")); Serial.print(vbat); Serial.println(F(" mV")); 184 | } 185 | 186 | 187 | if (! fona.getBattPercent(&vbat)) { 188 | Serial.println(F("Failed to read Batt")); 189 | } else { 190 | Serial.print(F("VPct = ")); Serial.print(vbat); Serial.println(F("%")); 191 | } 192 | 193 | break; 194 | } 195 | 196 | case 'U': { 197 | // Unlock the SIM with a PIN code 198 | char PIN[5]; 199 | flushSerial(); 200 | Serial.println(F("Enter 4-digit PIN")); 201 | readline(PIN, 3); 202 | Serial.println(PIN); 203 | Serial.print(F("Unlocking SIM card: ")); 204 | if (! fona.unlockSIM(PIN)) { 205 | Serial.println(F("Failed")); 206 | } else { 207 | Serial.println(F("OK!")); 208 | } 209 | break; 210 | } 211 | 212 | case 'C': { 213 | // read the CCID 214 | fona.getSIMCCID(replybuffer); // make sure replybuffer is at least 21 bytes! 215 | Serial.print(F("SIM CCID = ")); Serial.println(replybuffer); 216 | break; 217 | } 218 | 219 | case 'i': { 220 | // read the RSSI 221 | uint8_t n = fona.getRSSI(); 222 | int8_t r; 223 | 224 | Serial.print(F("RSSI = ")); Serial.print(n); Serial.print(": "); 225 | if (n == 0) r = -115; 226 | if (n == 1) r = -111; 227 | if (n == 31) r = -52; 228 | if ((n >= 2) && (n <= 30)) { 229 | r = map(n, 2, 30, -110, -54); 230 | } 231 | Serial.print(r); Serial.println(F(" dBm")); 232 | 233 | break; 234 | } 235 | 236 | case 'n': { 237 | // read the network/cellular status 238 | uint8_t n = fona.getNetworkStatus(); 239 | Serial.print(F("Network status ")); 240 | Serial.print(n); 241 | Serial.print(F(": ")); 242 | if (n == 0) Serial.println(F("Not registered")); 243 | if (n == 1) Serial.println(F("Registered (home)")); 244 | if (n == 2) Serial.println(F("Not registered (searching)")); 245 | if (n == 3) Serial.println(F("Denied")); 246 | if (n == 4) Serial.println(F("Unknown")); 247 | if (n == 5) Serial.println(F("Registered roaming")); 248 | break; 249 | } 250 | 251 | /*** Audio ***/ 252 | case 'v': { 253 | // set volume 254 | flushSerial(); 255 | Serial.print(F("Set Vol %")); 256 | uint8_t vol = readnumber(); 257 | Serial.println(); 258 | if (! fona.setVolume(vol)) { 259 | Serial.println(F("Failed")); 260 | } else { 261 | Serial.println(F("OK!")); 262 | } 263 | break; 264 | } 265 | 266 | case 'V': { 267 | uint8_t v = fona.getVolume(); 268 | Serial.print(v); Serial.println("%"); 269 | 270 | break; 271 | } 272 | 273 | case 'H': { 274 | // Set Headphone output 275 | if (! fona.setAudio(FONA_HEADSETAUDIO)) { 276 | Serial.println(F("Failed")); 277 | } else { 278 | Serial.println(F("OK!")); 279 | } 280 | fona.setMicVolume(FONA_HEADSETAUDIO, 15); 281 | break; 282 | } 283 | case 'e': { 284 | // Set External output 285 | if (! fona.setAudio(FONA_EXTAUDIO)) { 286 | Serial.println(F("Failed")); 287 | } else { 288 | Serial.println(F("OK!")); 289 | } 290 | 291 | fona.setMicVolume(FONA_EXTAUDIO, 10); 292 | break; 293 | } 294 | 295 | case 'T': { 296 | // play tone 297 | flushSerial(); 298 | Serial.print(F("Play tone #")); 299 | uint8_t kittone = readnumber(); 300 | Serial.println(); 301 | // play for 1 second (1000 ms) 302 | if (! fona.playToolkitTone(kittone, 1000)) { 303 | Serial.println(F("Failed")); 304 | } else { 305 | Serial.println(F("OK!")); 306 | } 307 | break; 308 | } 309 | 310 | /*** FM Radio ***/ 311 | 312 | case 'f': { 313 | // get freq 314 | flushSerial(); 315 | Serial.print(F("FM Freq (eg 1011 == 101.1 MHz): ")); 316 | uint16_t station = readnumber(); 317 | Serial.println(); 318 | // FM radio ON using headset 319 | if (fona.FMradio(true, FONA_HEADSETAUDIO)) { 320 | Serial.println(F("Opened")); 321 | } 322 | if (! fona.tuneFMradio(station)) { 323 | Serial.println(F("Failed")); 324 | } else { 325 | Serial.println(F("Tuned")); 326 | } 327 | break; 328 | } 329 | case 'F': { 330 | // FM radio off 331 | if (! fona.FMradio(false)) { 332 | Serial.println(F("Failed")); 333 | } else { 334 | Serial.println(F("OK!")); 335 | } 336 | break; 337 | } 338 | case 'm': { 339 | // Set FM volume. 340 | flushSerial(); 341 | Serial.print(F("Set FM Vol [0-6]:")); 342 | uint8_t vol = readnumber(); 343 | Serial.println(); 344 | if (!fona.setFMVolume(vol)) { 345 | Serial.println(F("Failed")); 346 | } else { 347 | Serial.println(F("OK!")); 348 | } 349 | break; 350 | } 351 | case 'M': { 352 | // Get FM volume. 353 | uint8_t fmvol = fona.getFMVolume(); 354 | if (fmvol < 0) { 355 | Serial.println(F("Failed")); 356 | } else { 357 | Serial.print(F("FM volume: ")); 358 | Serial.println(fmvol, DEC); 359 | } 360 | break; 361 | } 362 | case 'q': { 363 | // Get FM station signal level (in decibels). 364 | flushSerial(); 365 | Serial.print(F("FM Freq (eg 1011 == 101.1 MHz): ")); 366 | uint16_t station = readnumber(); 367 | Serial.println(); 368 | int8_t level = fona.getFMSignalLevel(station); 369 | if (level < 0) { 370 | Serial.println(F("Failed! Make sure FM radio is on (tuned to station).")); 371 | } else { 372 | Serial.print(F("Signal level (dB): ")); 373 | Serial.println(level, DEC); 374 | } 375 | break; 376 | } 377 | 378 | /*** PWM ***/ 379 | 380 | case 'P': { 381 | // PWM Buzzer output @ 2KHz max 382 | flushSerial(); 383 | Serial.print(F("PWM Freq, 0 = Off, (1-2000): ")); 384 | uint16_t freq= readnumber(); 385 | Serial.println(); 386 | if (! fona.setPWM(freq)) { 387 | Serial.println(F("Failed")); 388 | } else { 389 | Serial.println(F("OK!")); 390 | } 391 | break; 392 | } 393 | 394 | /*** Call ***/ 395 | case 'c': { 396 | // call a phone! 397 | char number[30]; 398 | flushSerial(); 399 | Serial.print(F("Call #")); 400 | readline(number, 30); 401 | Serial.println(); 402 | Serial.print(F("Calling ")); Serial.println(number); 403 | if (!fona.callPhone(number)) { 404 | Serial.println(F("Failed")); 405 | } else { 406 | Serial.println(F("Sent!")); 407 | } 408 | 409 | break; 410 | } 411 | case 'h': { 412 | // hang up! 413 | if (! fona.hangUp()) { 414 | Serial.println(F("Failed")); 415 | } else { 416 | Serial.println(F("OK!")); 417 | } 418 | break; 419 | } 420 | 421 | case 'p': { 422 | // pick up! 423 | if (! fona.pickUp()) { 424 | Serial.println(F("Failed")); 425 | } else { 426 | Serial.println(F("OK!")); 427 | } 428 | break; 429 | } 430 | 431 | /*** SMS ***/ 432 | 433 | case 'N': { 434 | // read the number of SMS's! 435 | int8_t smsnum = fona.getNumSMS(); 436 | if (smsnum < 0) { 437 | Serial.println(F("Could not read # SMS")); 438 | } else { 439 | Serial.print(smsnum); 440 | Serial.println(F(" SMS's on SIM card!")); 441 | } 442 | break; 443 | } 444 | case 'r': { 445 | // read an SMS 446 | flushSerial(); 447 | Serial.print(F("Read #")); 448 | uint8_t smsn = readnumber(); 449 | Serial.print(F("\n\rReading SMS #")); Serial.println(smsn); 450 | 451 | // Retrieve SMS sender address/phone number. 452 | if (! fona.getSMSSender(smsn, replybuffer, 250)) { 453 | Serial.println("Failed!"); 454 | break; 455 | } 456 | Serial.print(F("FROM: ")); Serial.println(replybuffer); 457 | 458 | // Retrieve SMS value. 459 | uint16_t smslen; 460 | if (! fona.readSMS(smsn, replybuffer, 250, &smslen)) { // pass in buffer and max len! 461 | Serial.println("Failed!"); 462 | break; 463 | } 464 | Serial.print(F("***** SMS #")); Serial.print(smsn); 465 | Serial.print(" ("); Serial.print(smslen); Serial.println(F(") bytes *****")); 466 | Serial.println(replybuffer); 467 | Serial.println(F("*****")); 468 | 469 | break; 470 | } 471 | case 'R': { 472 | // read all SMS 473 | int8_t smsnum = fona.getNumSMS(); 474 | uint16_t smslen; 475 | for (int8_t smsn=1; smsn<=smsnum; smsn++) { 476 | Serial.print(F("\n\rReading SMS #")); Serial.println(smsn); 477 | if (!fona.readSMS(smsn, replybuffer, 250, &smslen)) { // pass in buffer and max len! 478 | Serial.println(F("Failed!")); 479 | break; 480 | } 481 | // if the length is zero, its a special case where the index number is higher 482 | // so increase the max we'll look at! 483 | if (smslen == 0) { 484 | Serial.println(F("[empty slot]")); 485 | smsnum++; 486 | continue; 487 | } 488 | 489 | Serial.print(F("***** SMS #")); Serial.print(smsn); 490 | Serial.print(" ("); Serial.print(smslen); Serial.println(F(") bytes *****")); 491 | Serial.println(replybuffer); 492 | Serial.println(F("*****")); 493 | } 494 | break; 495 | } 496 | 497 | case 'd': { 498 | // delete an SMS 499 | flushSerial(); 500 | Serial.print(F("Delete #")); 501 | uint8_t smsn = readnumber(); 502 | 503 | Serial.print(F("\n\rDeleting SMS #")); Serial.println(smsn); 504 | if (fona.deleteSMS(smsn)) { 505 | Serial.println(F("OK!")); 506 | } else { 507 | Serial.println(F("Couldn't delete")); 508 | } 509 | break; 510 | } 511 | 512 | case 's': { 513 | // send an SMS! 514 | char sendto[21], message[141]; 515 | flushSerial(); 516 | Serial.print(F("Send to #")); 517 | readline(sendto, 20); 518 | Serial.println(sendto); 519 | Serial.print(F("Type out one-line message (140 char): ")); 520 | readline(message, 140); 521 | Serial.println(message); 522 | if (!fona.sendSMS(sendto, message)) { 523 | Serial.println(F("Failed")); 524 | } else { 525 | Serial.println(F("Sent!")); 526 | } 527 | 528 | break; 529 | } 530 | 531 | /*** Time ***/ 532 | 533 | case 'y': { 534 | // enable network time sync 535 | if (!fona.enableNetworkTimeSync(true)) 536 | Serial.println(F("Failed to enable")); 537 | break; 538 | } 539 | 540 | case 'Y': { 541 | // enable NTP time sync 542 | if (!fona.enableNTPTimeSync(true, F("pool.ntp.org"))) 543 | Serial.println(F("Failed to enable")); 544 | break; 545 | } 546 | 547 | case 't': { 548 | // read the time 549 | char buffer[23]; 550 | 551 | fona.getTime(buffer, 23); // make sure replybuffer is at least 23 bytes! 552 | Serial.print(F("Time = ")); Serial.println(buffer); 553 | break; 554 | } 555 | 556 | 557 | /*********************************** GPS (SIM808 only) */ 558 | 559 | case 'o': { 560 | // turn GPS off 561 | if (!fona.enableGPS(false)) 562 | Serial.println(F("Failed to turn off")); 563 | break; 564 | } 565 | case 'O': { 566 | // turn GPS on 567 | if (!fona.enableGPS(true)) 568 | Serial.println(F("Failed to turn on")); 569 | break; 570 | } 571 | case 'x': { 572 | int8_t stat; 573 | // check GPS fix 574 | stat = fona.GPSstatus(); 575 | if (stat < 0) 576 | Serial.println(F("Failed to query")); 577 | if (stat == 0) Serial.println(F("GPS off")); 578 | if (stat == 1) Serial.println(F("No fix")); 579 | if (stat == 2) Serial.println(F("2D fix")); 580 | if (stat == 3) Serial.println(F("3D fix")); 581 | break; 582 | } 583 | 584 | case 'L': { 585 | // check for GPS location 586 | char gpsdata[80]; 587 | fona.getGPS(0, gpsdata, 80); 588 | Serial.println(F("Reply in format: mode,longitude,latitude,altitude,utctime(yyyymmddHHMMSS),ttff,satellites,speed,course")); 589 | Serial.println(gpsdata); 590 | 591 | break; 592 | } 593 | 594 | case 'E': { 595 | flushSerial(); 596 | Serial.print(F("GPS NMEA output sentences (0 = off, 34 = RMC+GGA, 255 = all)")); 597 | uint8_t nmeaout = readnumber(); 598 | 599 | // turn on NMEA output 600 | fona.enableGPSNMEA(nmeaout); 601 | 602 | break; 603 | } 604 | 605 | /*********************************** GPRS */ 606 | 607 | case 'g': { 608 | // turn GPRS off 609 | if (!fona.enableGPRS(false)) 610 | Serial.println(F("Failed to turn off")); 611 | break; 612 | } 613 | case 'G': { 614 | // turn GPRS on 615 | if (!fona.enableGPRS(true)) 616 | Serial.println(F("Failed to turn on")); 617 | break; 618 | } 619 | case 'l': { 620 | // check for GSMLOC (requires GPRS) 621 | uint16_t returncode; 622 | 623 | if (!fona.getGSMLoc(&returncode, replybuffer, 250)) 624 | Serial.println(F("Failed!")); 625 | if (returncode == 0) { 626 | Serial.println(replybuffer); 627 | } else { 628 | Serial.print(F("Fail code #")); Serial.println(returncode); 629 | } 630 | 631 | break; 632 | } 633 | case 'w': { 634 | // read website URL 635 | uint16_t statuscode; 636 | int16_t length; 637 | char url[80]; 638 | 639 | flushSerial(); 640 | Serial.println(F("NOTE: in beta! Use small webpages to read!")); 641 | Serial.println(F("URL to read (e.g. www.adafruit.com/testwifi/index.html):")); 642 | Serial.print(F("http://")); readline(url, 79); 643 | Serial.println(url); 644 | 645 | Serial.println(F("****")); 646 | if (!fona.HTTP_GET_start(url, &statuscode, (uint16_t *)&length)) { 647 | Serial.println("Failed!"); 648 | break; 649 | } 650 | while (length > 0) { 651 | while (fona.available()) { 652 | char c = fona.read(); 653 | 654 | // Serial.write is too slow, we'll write directly to Serial register! 655 | #if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) 656 | loop_until_bit_is_set(UCSR0A, UDRE0); /* Wait until data register empty. */ 657 | UDR0 = c; 658 | #else 659 | Serial.write(c); 660 | #endif 661 | length--; 662 | if (! length) break; 663 | } 664 | } 665 | Serial.println(F("\n****")); 666 | fona.HTTP_GET_end(); 667 | break; 668 | } 669 | 670 | case 'W': { 671 | // Post data to website 672 | uint16_t statuscode; 673 | int16_t length; 674 | char url[80]; 675 | char data[80]; 676 | 677 | flushSerial(); 678 | Serial.println(F("NOTE: in beta! Use simple websites to post!")); 679 | Serial.println(F("URL to post (e.g. httpbin.org/post):")); 680 | Serial.print(F("http://")); readline(url, 79); 681 | Serial.println(url); 682 | Serial.println(F("Data to post (e.g. \"foo\" or \"{\"simple\":\"json\"}\"):")); 683 | readline(data, 79); 684 | Serial.println(data); 685 | 686 | Serial.println(F("****")); 687 | if (!fona.HTTP_POST_start(url, F("text/plain"), (uint8_t *) data, strlen(data), &statuscode, (uint16_t *)&length)) { 688 | Serial.println("Failed!"); 689 | break; 690 | } 691 | while (length > 0) { 692 | while (fona.available()) { 693 | char c = fona.read(); 694 | 695 | #if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) 696 | loop_until_bit_is_set(UCSR0A, UDRE0); /* Wait until data register empty. */ 697 | UDR0 = c; 698 | #else 699 | Serial.write(c); 700 | #endif 701 | 702 | length--; 703 | if (! length) break; 704 | } 705 | } 706 | Serial.println(F("\n****")); 707 | fona.HTTP_POST_end(); 708 | break; 709 | } 710 | /*****************************************/ 711 | 712 | case 'S': { 713 | Serial.println(F("Creating SERIAL TUBE")); 714 | while (1) { 715 | while (Serial.available()) { 716 | delay(1); 717 | fona.write(Serial.read()); 718 | } 719 | if (fona.available()) { 720 | Serial.write(fona.read()); 721 | } 722 | } 723 | break; 724 | } 725 | 726 | default: { 727 | Serial.println(F("Unknown command")); 728 | printMenu(); 729 | break; 730 | } 731 | } 732 | // flush input 733 | flushSerial(); 734 | while (fona.available()) { 735 | Serial.write(fona.read()); 736 | } 737 | 738 | } 739 | 740 | void flushSerial() { 741 | while (Serial.available()) 742 | Serial.read(); 743 | } 744 | 745 | char readBlocking() { 746 | while (!Serial.available()); 747 | return Serial.read(); 748 | } 749 | uint16_t readnumber() { 750 | uint16_t x = 0; 751 | char c; 752 | while (! isdigit(c = readBlocking())) { 753 | //Serial.print(c); 754 | } 755 | Serial.print(c); 756 | x = c - '0'; 757 | while (isdigit(c = readBlocking())) { 758 | Serial.print(c); 759 | x *= 10; 760 | x += c - '0'; 761 | } 762 | return x; 763 | } 764 | 765 | uint8_t readline(char *buff, uint8_t maxbuff, uint16_t timeout) { 766 | uint16_t buffidx = 0; 767 | boolean timeoutvalid = true; 768 | if (timeout == 0) timeoutvalid = false; 769 | 770 | while (true) { 771 | if (buffidx > maxbuff) { 772 | //Serial.println(F("SPACE")); 773 | break; 774 | } 775 | 776 | while(Serial.available()) { 777 | char c = Serial.read(); 778 | 779 | //Serial.print(c, HEX); Serial.print("#"); Serial.println(c); 780 | 781 | if (c == '\r') continue; 782 | if (c == 0xA) { 783 | if (buffidx == 0) // the first 0x0A is ignored 784 | continue; 785 | 786 | timeout = 0; // the second 0x0A is the end of the line 787 | timeoutvalid = true; 788 | break; 789 | } 790 | buff[buffidx] = c; 791 | buffidx++; 792 | } 793 | 794 | if (timeoutvalid && timeout == 0) { 795 | //Serial.println(F("TIMEOUT")); 796 | break; 797 | } 798 | delay(1); 799 | } 800 | buff[buffidx] = 0; // null term 801 | return buffidx; 802 | } 803 | -------------------------------------------------------------------------------- /examples/GPS/GPS.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * ___ ___ _ _ _ ___ __ ___ ___ ___ ___ 3 | * | __/ _ \| \| | /_\ ( _ )/ \( _ ) / __| _ \/ __| 4 | * | _| (_) | .` |/ _ \ / _ \ () / _ \ | (_ | _/\__ \ 5 | * |_| \___/|_|\_/_/ \_\ \___/\__/\___/ \___|_| |___/ 6 | * 7 | * This example is meant to work with the Adafruit 8 | * FONA 808 Shield or Breakout. 9 | * 10 | * Copyright: 2015 Adafruit 11 | * Author: Todd Treece 12 | * Licence: MIT 13 | * 14 | */ 15 | #include "Adafruit_FONA.h" 16 | 17 | // standard pins for the 808 shield 18 | #define FONA_RX 3 19 | #define FONA_TX 4 20 | #define FONA_RST 5 21 | 22 | // This is to handle the absence of software serial on platforms 23 | // like the Arduino Due. Modify this code if you are using different 24 | // hardware serial port, or if you are using a non-avr platform 25 | // that supports software serial. 26 | #ifdef __AVR__ 27 | #include 28 | SoftwareSerial fonaSS = SoftwareSerial(FONA_TX, FONA_RX); 29 | SoftwareSerial *fonaSerial = &fonaSS; 30 | #else 31 | HardwareSerial *fonaSerial = &Serial1; 32 | #endif 33 | 34 | Adafruit_FONA fona = Adafruit_FONA(FONA_RST); 35 | 36 | void setup() { 37 | 38 | while (! Serial); 39 | 40 | Serial.begin(115200); 41 | Serial.println(F("Adafruit FONA 808 GPS demo")); 42 | Serial.println(F("Initializing FONA... (May take a few seconds)")); 43 | 44 | fonaSerial->begin(4800); 45 | if (! fona.begin(*fonaSerial)) { 46 | Serial.println(F("Couldn't find FONA")); 47 | while(1); 48 | } 49 | Serial.println(F("FONA is OK")); 50 | 51 | Serial.println(F("Enabling GPS...")); 52 | fona.enableGPS(true); 53 | delay(5000); 54 | 55 | } 56 | 57 | void loop() { 58 | 59 | float latitude, longitude, speed_kph, heading, speed_mph, altitude; 60 | 61 | // if you ask for an altitude reading, getGPS will return false if there isn't a 3D fix 62 | boolean gps_success = fona.getGPS(&latitude, &longitude, &speed_kph, &heading, &altitude); 63 | 64 | if (gps_success) { 65 | 66 | Serial.print("GPS lat:"); 67 | Serial.println(latitude); 68 | Serial.print("GPS long:"); 69 | Serial.println(longitude); 70 | Serial.print("GPS speed KPH:"); 71 | Serial.println(speed_kph); 72 | Serial.print("GPS speed MPH:"); 73 | speed_mph = speed_kph * 0.621371192; 74 | Serial.println(speed_mph); 75 | Serial.print("GPS heading:"); 76 | Serial.println(heading); 77 | Serial.print("GPS altitude:"); 78 | Serial.println(altitude); 79 | 80 | } else { 81 | Serial.println("Waiting for FONA 808 GPS 3D fix..."); 82 | } 83 | 84 | // print out the GSM location to compare 85 | boolean gsmloc_success = fona.getGSMLoc(&latitude, &longitude); 86 | 87 | if (gsmloc_success) { 88 | 89 | Serial.print("GSMLoc lat:"); 90 | Serial.println(latitude); 91 | Serial.print("GSMLoc long:"); 92 | Serial.println(longitude); 93 | 94 | } else { 95 | Serial.println("GSM location failed..."); 96 | } 97 | 98 | delay(2000); 99 | 100 | } 101 | -------------------------------------------------------------------------------- /examples/IncomingCall/IncomingCall.ino: -------------------------------------------------------------------------------- 1 | // FONA Incoming Call Number Example 2 | // Listens for a call and displays the phone number of the caller (if available). 3 | // Use this example to add phone call detection to your own FONA sketch. 4 | #include "Adafruit_FONA.h" 5 | 6 | // Pins which are connected to the FONA. 7 | // Note that this is different from FONAtest! 8 | #define FONA_RX 3 9 | #define FONA_TX 4 10 | #define FONA_RST 5 11 | 12 | // Note you need to map interrupt number to pin number 13 | // for your board. On an Uno & Mega interrupt 0 is 14 | // digital pin 2, and on a Leonardo interrupt 0 is 15 | // digital pin 3. See this page for a complete table: 16 | // http://arduino.cc/en/Reference/attachInterrupt 17 | // Make sure this interrupt pin is connected to FONA RI! 18 | #define FONA_RI_INTERRUPT 0 19 | 20 | // This is to handle the absence of software serial on platforms 21 | // like the Arduino Due. Modify this code if you are using different 22 | // hardware serial port, or if you are using a non-avr platform 23 | // that supports software serial. 24 | #ifdef __AVR__ 25 | #include 26 | SoftwareSerial fonaSS = SoftwareSerial(FONA_TX, FONA_RX); 27 | SoftwareSerial *fonaSerial = &fonaSS; 28 | #else 29 | HardwareSerial *fonaSerial = &Serial1; 30 | #endif 31 | 32 | Adafruit_FONA fona = Adafruit_FONA(FONA_RST); 33 | 34 | void setup() { 35 | Serial.begin(115200); 36 | Serial.println(F("FONA incoming call example")); 37 | Serial.println(F("Initializing....(May take 3 seconds)")); 38 | 39 | fonaSerial->begin(4800); 40 | if (! fona.begin(*fonaSerial)) { 41 | Serial.println(F("Couldn't find FONA")); 42 | while(1); 43 | } 44 | Serial.println(F("FONA is OK")); 45 | 46 | // Enable incoming call notification. 47 | if(fona.callerIdNotification(true, FONA_RI_INTERRUPT)) { 48 | Serial.println(F("Caller id notification enabled.")); 49 | } 50 | else { 51 | Serial.println(F("Caller id notification disabled")); 52 | } 53 | } 54 | 55 | void loop(){ 56 | // Create a small string buffer to hold incoming call number. 57 | char phone[32] = {0}; 58 | // Check for an incoming call. Will return true if a call is incoming. 59 | if(fona.incomingCallNumber(phone)){ 60 | Serial.println(F("RING!")); 61 | Serial.print(F("Phone Number: ")); 62 | Serial.println(phone); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=Adafruit FONA Library 2 | version=1.0.0 3 | author=Adafruit 4 | maintainer=Adafruit 5 | sentence=Arduino library for the Adafruit FONA 6 | paragraph=Arduino library for the Adafruit FONA 7 | category=Communication 8 | url=https://github.com/adafruit/Adafruit_FONA_Library 9 | architectures=* 10 | --------------------------------------------------------------------------------