Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of Adafruit_FONA_Library by
Adafruit_FONA.cpp
00001 /*************************************************** 00002 This is a library for our Adafruit FONA Cellular Module 00003 00004 Designed specifically to work with the Adafruit FONA 00005 ----> http://www.adafruit.com/products/1946 00006 ----> http://www.adafruit.com/products/1963 00007 00008 These displays use TTL Serial to communicate, 2 pins are required to 00009 interface 00010 Adafruit invests time and resources providing this open source code, 00011 please support Adafruit and open-source hardware by purchasing 00012 products from Adafruit! 00013 00014 Written by Limor Fried/Ladyada for Adafruit Industries. 00015 BSD license, all text above must be included in any redistribution 00016 ****************************************************/ 00017 00018 /* 00019 * Modified by Marc PLOUHINEC 27/06/2015 for use in mbed 00020 */ 00021 00022 /* 00023 * Modified by Crispin MUKALAY 31/08/2017 to read GPS coordinates using SIMCOM's GSM/GPS/BT SIM808 module 00024 */ 00025 00026 #include <algorithm> 00027 #include "Adafruit_FONA.h" 00028 00029 #define HIGH 1 00030 #define LOW 0 00031 00032 bool Adafruit_FONA::begin(int baudrate) { 00033 mySerial.baud(baudrate); 00034 mySerial.attach(this, &Adafruit_FONA::onSerialDataReceived, Serial::RxIrq); 00035 00036 _rstpin = HIGH; 00037 wait_ms(10); 00038 _rstpin = LOW; 00039 wait_ms(100); 00040 00041 _rstpin = HIGH; 00042 00043 // give 3 seconds to reboot 00044 wait_ms(3000); 00045 00046 while (readable()) getc(); 00047 00048 sendCheckReply("AT", "OK"); 00049 wait_ms(100); 00050 sendCheckReply("AT", "OK"); 00051 wait_ms(100); 00052 sendCheckReply("AT", "OK"); 00053 wait_ms(100); 00054 00055 // turn off Echo! 00056 sendCheckReply("ATE0", "OK"); 00057 wait_ms(100); 00058 00059 if (! sendCheckReply("ATE0", "OK")) { 00060 return false; 00061 } 00062 00063 return true; 00064 } 00065 00066 void Adafruit_FONA::setEventListener(EventListener *eventListener) { 00067 this->eventListener = eventListener; 00068 } 00069 00070 /********* Stream ********************************************/ 00071 00072 int Adafruit_FONA::_putc(int value) { 00073 return mySerial.putc(value); 00074 } 00075 00076 int Adafruit_FONA::_getc() { 00077 __disable_irq(); // Start Critical Section - don't interrupt while changing global buffer variables 00078 00079 // Wait for data if the buffer is empty 00080 if (isRxBufferEmpty()) { 00081 __enable_irq(); // End Critical Section - need to allow rx interrupt to get new characters for buffer 00082 00083 while(isRxBufferEmpty()); 00084 00085 __disable_irq(); // Start Critical Section - don't interrupt while changing global buffer variables 00086 } 00087 00088 int data = rxBuffer[rxBufferOutIndex]; 00089 incrementRxBufferOutIndex(); 00090 00091 __enable_irq(); // End Critical Section 00092 00093 return data; 00094 } 00095 00096 int Adafruit_FONA::readable() { 00097 return !isRxBufferEmpty(); 00098 } 00099 00100 void Adafruit_FONA::onSerialDataReceived() { 00101 while (mySerial.readable() && !isRxBufferFull()) { 00102 int data = mySerial.getc(); 00103 rxBuffer[rxBufferInIndex] = data; 00104 00105 // 00106 // Analyze the received data in order to detect events like RING or NO CARRIER 00107 // 00108 00109 // Copy the data in the current line 00110 if (currentReceivedLineSize < RX_BUFFER_SIZE && data != '\r' && data != '\n') { 00111 currentReceivedLine[currentReceivedLineSize] = (char) data; 00112 currentReceivedLineSize++; 00113 } 00114 00115 // Check if the line is complete 00116 if (data == '\n') { 00117 currentReceivedLine[currentReceivedLineSize] = 0; 00118 00119 if (eventListener != NULL) { 00120 // Check if we have a special event 00121 if (strcmp(currentReceivedLine, "RING") == 0) { 00122 eventListener->onRing(); 00123 } else if (strcmp(currentReceivedLine, "NO CARRIER") == 0) { 00124 eventListener->onNoCarrier(); 00125 } 00126 } 00127 00128 currentReceivedLineSize = 0; 00129 } 00130 00131 incrementRxBufferInIndex(); 00132 } 00133 } 00134 00135 /********* Real Time Clock ********************************************/ 00136 00137 bool Adafruit_FONA::enableRTC(uint8_t i) { 00138 if (! sendCheckReply("AT+CLTS=", i, "OK")) 00139 return false; 00140 return sendCheckReply("AT&W", "OK"); 00141 } 00142 00143 /********* BATTERY & ADC ********************************************/ 00144 00145 /* returns value in mV (uint16_t) */ 00146 bool Adafruit_FONA::getBattVoltage(uint16_t *v) { 00147 return sendParseReply("AT+CBC", "+CBC: ", v, ',', 2); 00148 } 00149 00150 /* returns the percentage charge of battery as reported by sim800 */ 00151 bool Adafruit_FONA::getBattPercent(uint16_t *p) { 00152 return sendParseReply("AT+CBC", "+CBC: ", p, ',', 1); 00153 } 00154 00155 bool Adafruit_FONA::getADCVoltage(uint16_t *v) { 00156 return sendParseReply("AT+CADC?", "+CADC: 1,", v); 00157 } 00158 00159 /********* SIM ***********************************************************/ 00160 00161 bool Adafruit_FONA::unlockSIM(char *pin) 00162 { 00163 char sendbuff[14] = "AT+CPIN="; 00164 sendbuff[8] = pin[0]; 00165 sendbuff[9] = pin[1]; 00166 sendbuff[10] = pin[2]; 00167 sendbuff[11] = pin[3]; 00168 sendbuff[12] = NULL; 00169 00170 return sendCheckReply(sendbuff, "OK"); 00171 } 00172 00173 uint8_t Adafruit_FONA::getSIMCCID(char *ccid) { 00174 getReply("AT+CCID"); 00175 // up to 20 chars 00176 strncpy(ccid, replybuffer, 20); 00177 ccid[20] = 0; 00178 00179 readline(); // eat 'OK' 00180 00181 return strlen(ccid); 00182 } 00183 00184 /********* IMEI **********************************************************/ 00185 00186 uint8_t Adafruit_FONA::getIMEI(char *imei) { 00187 getReply("AT+GSN"); 00188 00189 // up to 15 chars 00190 strncpy(imei, replybuffer, 15); 00191 imei[15] = 0; 00192 00193 readline(); // eat 'OK' 00194 00195 return strlen(imei); 00196 } 00197 00198 /********* NETWORK *******************************************************/ 00199 00200 uint8_t Adafruit_FONA::getNetworkStatus(void) { 00201 uint16_t status; 00202 00203 if (! sendParseReply("AT+CREG?", "+CREG: ", &status, ',', 1)) return 0; 00204 00205 return status; 00206 } 00207 00208 00209 uint8_t Adafruit_FONA::getRSSI(void) { 00210 uint16_t reply; 00211 00212 if (! sendParseReply("AT+CSQ", "+CSQ: ", &reply) ) return 0; 00213 00214 return reply; 00215 } 00216 00217 /********* AUDIO *******************************************************/ 00218 00219 bool Adafruit_FONA::setAudio(uint8_t a) { 00220 // 0 is headset, 1 is external audio 00221 if (a > 1) return false; 00222 00223 return sendCheckReply("AT+CHFA=", a, "OK"); 00224 } 00225 00226 uint8_t Adafruit_FONA::getVolume(void) { 00227 uint16_t reply; 00228 00229 if (! sendParseReply("AT+CLVL?", "+CLVL: ", &reply) ) return 0; 00230 00231 return reply; 00232 } 00233 00234 bool Adafruit_FONA::setVolume(uint8_t i) { 00235 return sendCheckReply("AT+CLVL=", i, "OK"); 00236 } 00237 00238 00239 bool Adafruit_FONA::playDTMF(char dtmf) { 00240 char str[4]; 00241 str[0] = '\"'; 00242 str[1] = dtmf; 00243 str[2] = '\"'; 00244 str[3] = 0; 00245 return sendCheckReply("AT+CLDTMF=3,", str, "OK"); 00246 } 00247 00248 bool Adafruit_FONA::playToolkitTone(uint8_t t, uint16_t len) { 00249 return sendCheckReply("AT+STTONE=1,", t, len, "OK"); 00250 } 00251 00252 bool Adafruit_FONA::setMicVolume(uint8_t a, uint8_t level) { 00253 // 0 is headset, 1 is external audio 00254 if (a > 1) return false; 00255 00256 return sendCheckReply("AT+CMIC=", a, level, "OK"); 00257 } 00258 00259 /********* FM RADIO *******************************************************/ 00260 00261 00262 bool Adafruit_FONA::FMradio(bool onoff, uint8_t a) { 00263 if (! onoff) { 00264 return sendCheckReply("AT+FMCLOSE", "OK"); 00265 } 00266 00267 // 0 is headset, 1 is external audio 00268 if (a > 1) return false; 00269 00270 return sendCheckReply("AT+FMOPEN=", a, "OK"); 00271 } 00272 00273 bool Adafruit_FONA::tuneFMradio(uint16_t station) { 00274 // Fail if FM station is outside allowed range. 00275 if ((station < 870) || (station > 1090)) 00276 return false; 00277 00278 return sendCheckReply("AT+FMFREQ=", station, "OK"); 00279 } 00280 00281 bool Adafruit_FONA::setFMVolume(uint8_t i) { 00282 // Fail if volume is outside allowed range (0-6). 00283 if (i > 6) { 00284 return false; 00285 } 00286 // Send FM volume command and verify response. 00287 return sendCheckReply("AT+FMVOLUME=", i, "OK"); 00288 } 00289 00290 int8_t Adafruit_FONA::getFMVolume() { 00291 uint16_t level; 00292 00293 if (! sendParseReply("AT+FMVOLUME?", "+FMVOLUME: ", &level) ) return 0; 00294 00295 return level; 00296 } 00297 00298 int8_t Adafruit_FONA::getFMSignalLevel(uint16_t station) { 00299 // Fail if FM station is outside allowed range. 00300 if ((station < 875) || (station > 1080)) { 00301 return -1; 00302 } 00303 00304 // Send FM signal level query command. 00305 // Note, need to explicitly send timeout so right overload is chosen. 00306 getReply("AT+FMSIGNAL=", station, FONA_DEFAULT_TIMEOUT_MS); 00307 // Check response starts with expected value. 00308 char *p = strstr(replybuffer, "+FMSIGNAL: "); 00309 if (p == 0) return -1; 00310 p+=11; 00311 // Find second colon to get start of signal quality. 00312 p = strchr(p, ':'); 00313 if (p == 0) return -1; 00314 p+=1; 00315 // Parse signal quality. 00316 int8_t level = atoi(p); 00317 readline(); // eat the "OK" 00318 return level; 00319 } 00320 00321 /********* PWM/BUZZER **************************************************/ 00322 00323 bool Adafruit_FONA::setPWM(uint16_t period, uint8_t duty) { 00324 if (period > 2000) return false; 00325 if (duty > 100) return false; 00326 00327 return sendCheckReply("AT+SPWM=0,", period, duty, "OK"); 00328 } 00329 00330 /********* CALL PHONES **************************************************/ 00331 bool Adafruit_FONA::callPhone(char *number) { 00332 char sendbuff[35] = "ATD"; 00333 strncpy(sendbuff+3, number, min((int)30, (int)strlen(number))); 00334 uint8_t x = strlen(sendbuff); 00335 sendbuff[x] = ';'; 00336 sendbuff[x+1] = 0; 00337 00338 return sendCheckReply(sendbuff, "OK"); 00339 } 00340 00341 bool Adafruit_FONA::hangUp(void) { 00342 return sendCheckReply("ATH0", "OK"); 00343 } 00344 00345 bool Adafruit_FONA::pickUp(void) { 00346 return sendCheckReply("ATA", "OK"); 00347 } 00348 00349 void Adafruit_FONA::onIncomingCall() { 00350 #ifdef ADAFRUIT_FONA_DEBUG 00351 printf("> Incoming call...\r\n"); 00352 #endif 00353 _incomingCall = true; 00354 } 00355 00356 bool Adafruit_FONA::callerIdNotification(bool enable) { 00357 if(enable){ 00358 _ringIndicatorInterruptIn.fall(this, &Adafruit_FONA::onIncomingCall); 00359 return sendCheckReply("AT+CLIP=1", "OK"); 00360 } 00361 00362 _ringIndicatorInterruptIn.fall(NULL); 00363 return sendCheckReply("AT+CLIP=0", "OK"); 00364 } 00365 00366 bool Adafruit_FONA::incomingCallNumber(char* phonenum) { 00367 //+CLIP: "<incoming phone number>",145,"",0,"",0 00368 if(!_incomingCall) 00369 return false; 00370 00371 readline(); 00372 while(!strcmp(replybuffer, "RING") == 0) { 00373 flushInput(); 00374 readline(); 00375 } 00376 00377 readline(); //reads incoming phone number line 00378 00379 parseReply("+CLIP: \"", phonenum, '"'); 00380 00381 #ifdef ADAFRUIT_FONA_DEBUG 00382 printf("Phone Number: %s\r\n", replybuffer); 00383 #endif 00384 00385 _incomingCall = false; 00386 return true; 00387 } 00388 00389 /********* SMS **********************************************************/ 00390 00391 uint8_t Adafruit_FONA::getSMSInterrupt(void) { 00392 uint16_t reply; 00393 00394 if (! sendParseReply("AT+CFGRI?", "+CFGRI: ", &reply) ) return 0; 00395 00396 return reply; 00397 } 00398 00399 bool Adafruit_FONA::setSMSInterrupt(uint8_t i) { 00400 return sendCheckReply("AT+CFGRI=", i, "OK"); 00401 } 00402 00403 int8_t Adafruit_FONA::getNumSMS(void) { 00404 uint16_t numsms; 00405 00406 if (! sendCheckReply("AT+CMGF=1", "OK")) return -1; 00407 // ask how many sms are stored 00408 00409 if (! sendParseReply("AT+CPMS?", "+CPMS: \"SM_P\",", &numsms) ) return -1; 00410 00411 return numsms; 00412 } 00413 00414 // Reading SMS's is a bit involved so we don't use helpers that may cause delays or debug 00415 // printouts! 00416 bool Adafruit_FONA::readSMS(uint8_t i, char *smsbuff, uint16_t maxlen, uint16_t *readlen) { 00417 // text mode 00418 if (! sendCheckReply("AT+CMGF=1", "OK")) return false; 00419 00420 // show all text mode parameters 00421 if (! sendCheckReply("AT+CSDH=1", "OK")) return false; 00422 00423 // parse out the SMS len 00424 uint16_t thesmslen = 0; 00425 00426 //getReply(F("AT+CMGR="), i, 1000); // do not print debug! 00427 mySerial.printf("AT+CMGR=%d\r\n", i); 00428 readline(1000); // timeout 00429 00430 // parse it out... 00431 if (! parseReply("+CMGR:", &thesmslen, ',', 11)) { 00432 *readlen = 0; 00433 return false; 00434 } 00435 00436 readRaw(thesmslen); 00437 00438 flushInput(); 00439 00440 uint16_t thelen = min(maxlen, (uint16_t)strlen(replybuffer)); 00441 strncpy(smsbuff, replybuffer, thelen); 00442 smsbuff[thelen] = 0; // end the string 00443 00444 #ifdef ADAFRUIT_FONA_DEBUG 00445 printf("%s\r\n", replybuffer); 00446 #endif 00447 *readlen = thelen; 00448 return true; 00449 } 00450 00451 // Retrieve the sender of the specified SMS message and copy it as a string to 00452 // the sender buffer. Up to senderlen characters of the sender will be copied 00453 // and a null terminator will be added if less than senderlen charactesr are 00454 // copied to the result. Returns true if a result was successfully retrieved, 00455 // otherwise false. 00456 bool Adafruit_FONA::getSMSSender(uint8_t i, char *sender, int senderlen) { 00457 // Ensure text mode and all text mode parameters are sent. 00458 if (! sendCheckReply("AT+CMGF=1", "OK")) return false; 00459 if (! sendCheckReply("AT+CSDH=1", "OK")) return false; 00460 // Send command to retrieve SMS message and parse a line of response. 00461 mySerial.printf("AT+CMGR=%d\r\n", i); 00462 readline(1000); 00463 // Parse the second field in the response. 00464 bool result = parseReplyQuoted("+CMGR:", sender, senderlen, ',', 1); 00465 // Drop any remaining data from the response. 00466 flushInput(); 00467 return result; 00468 } 00469 00470 bool Adafruit_FONA::sendSMS(char *smsaddr, char *smsmsg) { 00471 if (! sendCheckReply("AT+CMGF=1", "OK")) return -1; 00472 00473 char sendcmd[30] = "AT+CMGS=\""; 00474 strncpy(sendcmd+9, smsaddr, 30-9-2); // 9 bytes beginning, 2 bytes for close quote + null 00475 sendcmd[strlen(sendcmd)] = '\"'; 00476 00477 if (! sendCheckReply(sendcmd, "> ")) return false; 00478 #ifdef ADAFRUIT_FONA_DEBUG 00479 printf("> %s\r\n", smsmsg); 00480 #endif 00481 mySerial.printf("%s\r\n\r\n", smsmsg); 00482 mySerial.putc(0x1A); 00483 #ifdef ADAFRUIT_FONA_DEBUG 00484 printf("^Z\r\n"); 00485 #endif 00486 readline(10000); // read the +CMGS reply, wait up to 10 seconds!!! 00487 //Serial.print("* "); Serial.println(replybuffer); 00488 if (strstr(replybuffer, "+CMGS") == 0) { 00489 return false; 00490 } 00491 readline(1000); // read OK 00492 //Serial.print("* "); Serial.println(replybuffer); 00493 00494 if (strcmp(replybuffer, "OK") != 0) { 00495 return false; 00496 } 00497 00498 return true; 00499 } 00500 00501 00502 bool Adafruit_FONA::deleteSMS(uint8_t i) { 00503 if (! sendCheckReply("AT+CMGF=1", "OK")) return -1; 00504 // read an sms 00505 char sendbuff[12] = "AT+CMGD=000"; 00506 sendbuff[8] = (i / 100) + '0'; 00507 i %= 100; 00508 sendbuff[9] = (i / 10) + '0'; 00509 i %= 10; 00510 sendbuff[10] = i + '0'; 00511 00512 return sendCheckReply(sendbuff, "OK", 2000); 00513 } 00514 00515 /********* TIME **********************************************************/ 00516 00517 bool Adafruit_FONA::enableNetworkTimeSync(bool onoff) { 00518 if (onoff) { 00519 if (! sendCheckReply("AT+CLTS=1", "OK")) 00520 return false; 00521 } else { 00522 if (! sendCheckReply("AT+CLTS=0", "OK")) 00523 return false; 00524 } 00525 00526 flushInput(); // eat any 'Unsolicted Result Code' 00527 00528 return true; 00529 } 00530 00531 bool Adafruit_FONA::enableNTPTimeSync(bool onoff, const char* ntpserver) { 00532 if (onoff) { 00533 if (! sendCheckReply("AT+CNTPCID=1", "OK")) 00534 return false; 00535 00536 mySerial.printf("AT+CNTP=\""); 00537 if (ntpserver != 0) { 00538 mySerial.printf(ntpserver); 00539 } else { 00540 mySerial.printf("pool.ntp.org"); 00541 } 00542 mySerial.printf("\",0\r\n"); 00543 readline(FONA_DEFAULT_TIMEOUT_MS); 00544 if (strcmp(replybuffer, "OK") != 0) 00545 return false; 00546 00547 if (! sendCheckReply("AT+CNTP", "OK", 10000)) 00548 return false; 00549 00550 uint16_t status; 00551 readline(10000); 00552 if (! parseReply("+CNTP:", &status)) 00553 return false; 00554 } else { 00555 if (! sendCheckReply("AT+CNTPCID=0", "OK")) 00556 return false; 00557 } 00558 00559 return true; 00560 } 00561 00562 bool Adafruit_FONA::getTime(char* buff, uint16_t maxlen) { 00563 getReply("AT+CCLK?", (uint16_t) 10000); 00564 if (strncmp(replybuffer, "+CCLK: ", 7) != 0) 00565 return false; 00566 00567 char *p = replybuffer+7; 00568 uint16_t lentocopy = min((uint16_t)(maxlen-1), (uint16_t)strlen(p)); 00569 strncpy(buff, p, lentocopy+1); 00570 buff[lentocopy] = 0; 00571 00572 readline(); // eat OK 00573 00574 return true; 00575 } 00576 00577 /********* GPS **********************************************************/ 00578 00579 00580 bool Adafruit_FONA::enableGPS(bool onoff) { 00581 uint16_t state; 00582 00583 // first check if its already on or off 00584 if (! sendParseReply("AT+CGNSPWR?", "+CGNSPWR: ", &state) ) 00585 return false; 00586 00587 if (onoff && !state) { 00588 if (! sendCheckReply("AT+CGNSPWR=1", "OK")) 00589 return false; 00590 } else if (!onoff && state) { 00591 if (! sendCheckReply("AT+CGNSPWR=0", "OK")) 00592 return false; 00593 } 00594 return true; 00595 } 00596 00597 int8_t Adafruit_FONA::GPSstatus(void) { 00598 getReply("AT+CGPSSTATUS?"); 00599 00600 char *p = strstr(replybuffer, "+CGPSSTATUS: Location "); 00601 if (p == 0) return -1; 00602 00603 p+=22; 00604 00605 readline(); // eat 'OK' 00606 00607 00608 if (p[0] == 'U') return 0; 00609 if (p[0] == 'N') return 1; 00610 if (p[0] == '2') return 2; 00611 if (p[0] == '3') return 3; 00612 00613 // else 00614 return 0; 00615 } 00616 00617 uint8_t Adafruit_FONA::getGPSInfo(uint8_t arg, char *buffer, uint8_t maxbuff) { 00618 int32_t x = arg; 00619 00620 getReply("AT+CGNSINF"); 00621 00622 char *p = strstr(replybuffer, "+CGNSINF: "); 00623 if (p == 0){ 00624 buffer[0] = 0; 00625 return 0; 00626 } 00627 p+=9; 00628 uint8_t len = max((uint8_t)(maxbuff-1), (uint8_t)strlen(p)); 00629 strncpy(buffer, p, len); 00630 buffer[len] = 0; 00631 00632 readline(); // eat 'OK' 00633 return len; 00634 } 00635 00636 bool Adafruit_FONA::getGPS(float *fix, float *lat, float *lon,float *altitude, float *speed_kph, float *heading) { 00637 char gpsbuffer[120]; 00638 00639 // grab the mode 2^5 gps csv from the sim808 00640 uint8_t res_len = getGPSInfo(32, gpsbuffer, 120); 00641 00642 // make sure we have a response 00643 if (res_len == 0) 00644 return false; 00645 00646 // skip mode 00647 char *tok = strtok(gpsbuffer, ","); 00648 if (! tok) return false; 00649 00650 // grab fix 00651 char *fixp = strtok(NULL, ","); 00652 if (! fixp) return false; 00653 00654 *fix = atof(fixp); 00655 00656 // skip date 00657 tok = strtok(NULL, ","); 00658 if (! tok) return false; 00659 00660 // grab the latitude 00661 char *latp = strtok(NULL, ","); 00662 if (! latp) return false; 00663 00664 // grab longitude 00665 char *longp = strtok(NULL, ","); 00666 if (! longp) return false; 00667 00668 double latitude = atof(latp); 00669 double longitude = atof(longp); 00670 00671 *lat = latitude; 00672 *lon = longitude; 00673 00674 // grab altitude 00675 char *altp = strtok(NULL, ","); 00676 if (! altp) return false; 00677 00678 *altitude = atof(altp); 00679 00680 // only grab speed if needed 00681 if (speed_kph != NULL) { 00682 00683 // grab the speed in knots 00684 char *speedp = strtok(NULL, ","); 00685 if (! speedp) return false; 00686 00687 // convert to kph 00688 //*speed_kph = atof(speedp) * 1.852; 00689 *speed_kph = atof(speedp); 00690 00691 // grab heading 00692 char *headingp = strtok(NULL, ","); 00693 if (! headingp) return false; 00694 00695 *heading = atof(headingp); 00696 00697 00698 } 00699 00700 return true; 00701 } 00702 00703 bool Adafruit_FONA::enableGPSNMEA(uint8_t i) { 00704 char sendbuff[15] = "AT+CGPSOUT=000"; 00705 sendbuff[11] = (i / 100) + '0'; 00706 i %= 100; 00707 sendbuff[12] = (i / 10) + '0'; 00708 i %= 10; 00709 sendbuff[13] = i + '0'; 00710 00711 return sendCheckReply(sendbuff, "OK", 2000); 00712 } 00713 00714 00715 /********* GPRS **********************************************************/ 00716 00717 00718 bool Adafruit_FONA::enableGPRS(bool onoff) { 00719 if (onoff) { 00720 // disconnect all sockets 00721 sendCheckReply("AT+CIPSHUT", "SHUT OK", 5000); 00722 00723 if (! sendCheckReply("AT+CGATT=1", "OK", 10000)) 00724 return false; 00725 00726 // set bearer profile! connection type GPRS 00727 if (! sendCheckReply("AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"", "OK", 10000)) 00728 return false; 00729 00730 // set bearer profile access point name 00731 if (apn) { 00732 // Send command AT+SAPBR=3,1,"APN","<apn value>" where <apn value> is the configured APN value. 00733 if (! sendCheckReplyQuoted("AT+SAPBR=3,1,\"APN\",", apn, "OK", 10000)) 00734 return false; 00735 00736 // set username/password 00737 if (apnusername) { 00738 // Send command AT+SAPBR=3,1,"USER","<user>" where <user> is the configured APN username. 00739 if (! sendCheckReplyQuoted("AT+SAPBR=3,1,\"USER\",", apnusername, "OK", 10000)) 00740 return false; 00741 } 00742 if (apnpassword) { 00743 // Send command AT+SAPBR=3,1,"PWD","<password>" where <password> is the configured APN password. 00744 if (! sendCheckReplyQuoted("AT+SAPBR=3,1,\"PWD\",", apnpassword, "OK", 10000)) 00745 return false; 00746 } 00747 } 00748 00749 // open GPRS context 00750 if (! sendCheckReply("AT+SAPBR=1,1", "OK", 10000)) 00751 return false; 00752 } else { 00753 // disconnect all sockets 00754 if (! sendCheckReply("AT+CIPSHUT", "SHUT OK", 5000)) 00755 return false; 00756 00757 // close GPRS context 00758 if (! sendCheckReply("AT+SAPBR=0,1", "OK", 10000)) 00759 return false; 00760 00761 if (! sendCheckReply("AT+CGATT=0", "OK", 10000)) 00762 return false; 00763 } 00764 return true; 00765 } 00766 00767 uint8_t Adafruit_FONA::GPRSstate(void) { 00768 uint16_t state; 00769 00770 if (! sendParseReply("AT+CGATT?", "+CGATT: ", &state) ) 00771 return -1; 00772 00773 return state; 00774 } 00775 00776 void Adafruit_FONA::setGPRSNetworkSettings(const char* apn, const char* ausername, const char* apassword) { 00777 this->apn = (char*) apn; 00778 this->apnusername = (char*) ausername; 00779 this->apnpassword = (char*) apassword; 00780 } 00781 00782 bool Adafruit_FONA::getGSMLoc(uint16_t *errorcode, char *buff, uint16_t maxlen) { 00783 getReply("AT+CIPGSMLOC=1,1", (uint16_t)10000); 00784 00785 if (! parseReply("+CIPGSMLOC: ", errorcode)) 00786 return false; 00787 00788 char *p = replybuffer+14; 00789 uint16_t lentocopy = min((uint16_t)(maxlen-1), (uint16_t)strlen(p)); 00790 strncpy(buff, p, lentocopy+1); 00791 00792 readline(); // eat OK 00793 00794 return true; 00795 } 00796 00797 bool Adafruit_FONA::getGSMLoc(float *lat, float *lon) { 00798 uint16_t returncode; 00799 char gpsbuffer[120]; 00800 00801 // make sure we could get a response 00802 if (! getGSMLoc(&returncode, gpsbuffer, 120)) 00803 return false; 00804 00805 // make sure we have a valid return code 00806 if (returncode != 0) 00807 return false; 00808 00809 // tokenize the gps buffer to locate the lat & long 00810 char *latp = strtok(gpsbuffer, ","); 00811 if (! latp) return false; 00812 00813 char *longp = strtok(NULL, ","); 00814 if (! longp) return false; 00815 00816 *lat = atof(latp); 00817 *lon = atof(longp); 00818 00819 return true; 00820 } 00821 00822 /********* TCP FUNCTIONS ************************************/ 00823 00824 00825 bool Adafruit_FONA::TCPconnect(char *server, uint16_t port) { 00826 flushInput(); 00827 00828 // close all old connections 00829 if (! sendCheckReply("AT+CIPSHUT", "SHUT OK", 5000) ) return false; 00830 00831 // single connection at a time 00832 if (! sendCheckReply("AT+CIPMUX=0", "OK") ) return false; 00833 00834 // manually read data 00835 if (! sendCheckReply("AT+CIPRXGET=1", "OK") ) return false; 00836 00837 #ifdef ADAFRUIT_FONA_DEBUG 00838 printf("AT+CIPSTART=\"TCP\",\"%s\",\"%d\"\r\n", server, port); 00839 #endif 00840 00841 mySerial.printf("AT+CIPSTART=\"TCP\",\"%s\",\"%d\"\r\n", server, port); 00842 00843 if (! expectReply("OK")) return false; 00844 if (! expectReply("CONNECT OK")) return false; 00845 return true; 00846 } 00847 00848 bool Adafruit_FONA::TCPclose(void) { 00849 return sendCheckReply("AT+CIPCLOSE", "OK"); 00850 } 00851 00852 bool Adafruit_FONA::TCPconnected(void) { 00853 if (! sendCheckReply("AT+CIPSTATUS", "OK", 100) ) return false; 00854 readline(100); 00855 #ifdef ADAFRUIT_FONA_DEBUG 00856 printf("\t<--- %s\r\n", replybuffer); 00857 #endif 00858 return (strcmp(replybuffer, "STATE: CONNECT OK") == 0); 00859 } 00860 00861 bool Adafruit_FONA::TCPsend(char *packet, uint8_t len) { 00862 #ifdef ADAFRUIT_FONA_DEBUG 00863 printf("AT+CIPSEND=%d\r\n", len); 00864 00865 for (uint16_t i=0; i<len; i++) { 00866 printf(" 0x%#02x", packet[i]); 00867 } 00868 printf("\r\n"); 00869 #endif 00870 00871 00872 mySerial.printf("AT+CIPSEND=%d\r\n", len); 00873 readline(); 00874 #ifdef ADAFRUIT_FONA_DEBUG 00875 printf("\t<--- %s\r\n", replybuffer); 00876 #endif 00877 if (replybuffer[0] != '>') return false; 00878 00879 for (uint16_t i=0; i<len; i++) { 00880 mySerial.putc(packet[i]); 00881 } 00882 readline(3000); // wait up to 3 seconds to send the data 00883 #ifdef ADAFRUIT_FONA_DEBUG 00884 printf("\t<--- %s\r\n", replybuffer); 00885 #endif 00886 00887 return (strcmp(replybuffer, "SEND OK") == 0); 00888 } 00889 00890 uint16_t Adafruit_FONA::TCPavailable(void) { 00891 uint16_t avail; 00892 00893 if (! sendParseReply("AT+CIPRXGET=4", "+CIPRXGET: 4,", &avail, ',', 0) ) return false; 00894 00895 #ifdef ADAFRUIT_FONA_DEBUG 00896 printf("%d bytes available\r\n", avail); 00897 #endif 00898 00899 return avail; 00900 } 00901 00902 00903 uint16_t Adafruit_FONA::TCPread(uint8_t *buff, uint8_t len) { 00904 uint16_t avail; 00905 00906 mySerial.printf("AT+CIPRXGET=2,%d\r\n", len); 00907 readline(); 00908 if (! parseReply("+CIPRXGET: 2,", &avail, ',', 0)) return false; 00909 00910 readRaw(avail); 00911 00912 #ifdef ADAFRUIT_FONA_DEBUG 00913 printf("%d bytes read\r\n", avail); 00914 for (uint8_t i=0;i<avail;i++) { 00915 printf(" 0x%#02x", replybuffer[i]); 00916 } 00917 printf("\r\n"); 00918 #endif 00919 00920 memcpy(buff, replybuffer, avail); 00921 00922 return avail; 00923 } 00924 00925 /********* HTTP LOW LEVEL FUNCTIONS ************************************/ 00926 00927 bool Adafruit_FONA::HTTP_init() { 00928 return sendCheckReply("AT+HTTPINIT", "OK"); 00929 } 00930 00931 bool Adafruit_FONA::HTTP_term() { 00932 return sendCheckReply("AT+HTTPTERM", "OK"); 00933 } 00934 00935 void Adafruit_FONA::HTTP_para_start(const char* parameter, bool quoted) { 00936 flushInput(); 00937 00938 #ifdef ADAFRUIT_FONA_DEBUG 00939 printf("\t---> AT+HTTPPARA=\"%s\"\r\n", parameter); 00940 #endif 00941 00942 mySerial.printf("AT+HTTPPARA=\"%s", parameter); 00943 if (quoted) 00944 mySerial.printf("\",\""); 00945 else 00946 mySerial.printf("\","); 00947 } 00948 00949 bool Adafruit_FONA::HTTP_para_end(bool quoted) { 00950 if (quoted) 00951 mySerial.printf("\"\r\n"); 00952 else 00953 mySerial.printf("\r\n"); 00954 00955 return expectReply("OK"); 00956 } 00957 00958 bool Adafruit_FONA::HTTP_para(const char* parameter, const char* value) { 00959 HTTP_para_start(parameter, true); 00960 mySerial.printf(value); 00961 return HTTP_para_end(true); 00962 } 00963 00964 bool Adafruit_FONA::HTTP_para(const char* parameter, int32_t value) { 00965 HTTP_para_start(parameter, false); 00966 mySerial.printf("%d", value); 00967 return HTTP_para_end(false); 00968 } 00969 00970 bool Adafruit_FONA::HTTP_data(uint32_t size, uint32_t maxTime) { 00971 flushInput(); 00972 00973 #ifdef ADAFRUIT_FONA_DEBUG 00974 printf("\t---> AT+HTTPDATA=%d,%d\r\n", size, maxTime); 00975 #endif 00976 00977 mySerial.printf("AT+HTTPDATA=%d,%d\r\n", size, maxTime); 00978 00979 return expectReply("DOWNLOAD"); 00980 } 00981 00982 bool Adafruit_FONA::HTTP_action(uint8_t method, uint16_t *status, uint16_t *datalen, int32_t timeout) { 00983 // Send request. 00984 if (! sendCheckReply("AT+HTTPACTION=", method, "OK")) 00985 return false; 00986 00987 // Parse response status and size. 00988 readline(timeout); 00989 if (! parseReply("+HTTPACTION:", status, ',', 1)) 00990 return false; 00991 if (! parseReply("+HTTPACTION:", datalen, ',', 2)) 00992 return false; 00993 00994 return true; 00995 } 00996 00997 bool Adafruit_FONA::HTTP_readall(uint16_t *datalen) { 00998 getReply("AT+HTTPREAD"); 00999 if (! parseReply("+HTTPREAD:", datalen, ',', 0)) 01000 return false; 01001 01002 return true; 01003 } 01004 01005 bool Adafruit_FONA::HTTP_ssl(bool onoff) { 01006 return sendCheckReply("AT+HTTPSSL=", onoff ? 1 : 0, "OK"); 01007 } 01008 01009 /********* HTTP HIGH LEVEL FUNCTIONS ***************************/ 01010 01011 bool Adafruit_FONA::HTTP_GET_start(char *url, uint16_t *status, uint16_t *datalen){ 01012 if (! HTTP_setup(url)) 01013 return false; 01014 01015 // HTTP GET 01016 if (! HTTP_action(FONA_HTTP_GET, status, datalen)) 01017 return false; 01018 01019 #ifdef ADAFRUIT_FONA_DEBUG 01020 printf("Status: %d\r\n", *status); 01021 printf("Len: %d\r\n", *datalen); 01022 #endif 01023 01024 // HTTP response data 01025 if (! HTTP_readall(datalen)) 01026 return false; 01027 01028 return true; 01029 } 01030 01031 void Adafruit_FONA::HTTP_GET_end(void) { 01032 HTTP_term(); 01033 } 01034 01035 bool Adafruit_FONA::HTTP_POST_start(char *url, const char* contenttype, const uint8_t *postdata, uint16_t postdatalen, uint16_t *status, uint16_t *datalen) { 01036 if (! HTTP_setup(url)) 01037 return false; 01038 01039 if (! HTTP_para("CONTENT", contenttype)) { 01040 return false; 01041 } 01042 01043 // HTTP POST data 01044 if (! HTTP_data(postdatalen, 10000)) 01045 return false; 01046 for (uint16_t i = 0; i < postdatalen; i++) { 01047 mySerial.putc(postdata[i]); 01048 } 01049 if (! expectReply("OK")) 01050 return false; 01051 01052 // HTTP POST 01053 if (! HTTP_action(FONA_HTTP_POST, status, datalen)) 01054 return false; 01055 01056 #ifdef ADAFRUIT_FONA_DEBUG 01057 printf("Status: %d\r\n", *status); 01058 printf("Len: %d\r\n", *datalen); 01059 #endif 01060 01061 // HTTP response data 01062 if (! HTTP_readall(datalen)) 01063 return false; 01064 01065 return true; 01066 } 01067 01068 void Adafruit_FONA::HTTP_POST_end(void) { 01069 HTTP_term(); 01070 } 01071 01072 void Adafruit_FONA::setUserAgent(const char* useragent) { 01073 this->useragent = (char*) useragent; 01074 } 01075 01076 void Adafruit_FONA::setHTTPSRedirect(bool onoff) { 01077 httpsredirect = onoff; 01078 } 01079 01080 /********* HTTP HELPERS ****************************************/ 01081 01082 bool Adafruit_FONA::HTTP_setup(char *url) { 01083 // Handle any pending 01084 HTTP_term(); 01085 01086 // Initialize and set parameters 01087 if (! HTTP_init()) 01088 return false; 01089 if (! HTTP_para("CID", 1)) 01090 return false; 01091 if (! HTTP_para("UA", useragent)) 01092 return false; 01093 if (! HTTP_para("URL", url)) 01094 return false; 01095 01096 // HTTPS redirect 01097 if (httpsredirect) { 01098 if (! HTTP_para("REDIR",1)) 01099 return false; 01100 01101 if (! HTTP_ssl(true)) 01102 return false; 01103 } 01104 01105 return true; 01106 } 01107 01108 01109 /********* HELPERS *********************************************/ 01110 01111 bool Adafruit_FONA::expectReply(const char* reply, uint16_t timeout) { 01112 readline(timeout); 01113 #ifdef ADAFRUIT_FONA_DEBUG 01114 printf("\t<--- %s\r\n", replybuffer); 01115 #endif 01116 return (strcmp(replybuffer, reply) == 0); 01117 } 01118 01119 /********* LOW LEVEL *******************************************/ 01120 01121 void Adafruit_FONA::flushInput() { 01122 // Read all available serial input to flush pending data. 01123 uint16_t timeoutloop = 0; 01124 while (timeoutloop++ < 40) { 01125 while(readable()) { 01126 getc(); 01127 timeoutloop = 0; // If char was received reset the timer 01128 } 01129 wait_ms(1); 01130 } 01131 } 01132 01133 uint16_t Adafruit_FONA::readRaw(uint16_t b) { 01134 uint16_t idx = 0; 01135 01136 while (b && (idx < sizeof(replybuffer)-1)) { 01137 if (readable()) { 01138 replybuffer[idx] = getc(); 01139 idx++; 01140 b--; 01141 } 01142 } 01143 replybuffer[idx] = 0; 01144 01145 return idx; 01146 } 01147 01148 uint8_t Adafruit_FONA::readline(uint16_t timeout, bool multiline) { 01149 uint16_t replyidx = 0; 01150 01151 while (timeout--) { 01152 if (replyidx >= 254) { 01153 break; 01154 } 01155 01156 while(readable()) { 01157 char c = getc(); 01158 if (c == '\r') continue; 01159 if (c == 0xA) { 01160 if (replyidx == 0) // the first 0x0A is ignored 01161 continue; 01162 01163 if (!multiline) { 01164 timeout = 0; // the second 0x0A is the end of the line 01165 break; 01166 } 01167 } 01168 replybuffer[replyidx] = c; 01169 replyidx++; 01170 } 01171 01172 if (timeout == 0) { 01173 break; 01174 } 01175 wait_ms(1); 01176 } 01177 replybuffer[replyidx] = 0; // null term 01178 return replyidx; 01179 } 01180 01181 uint8_t Adafruit_FONA::getReply(const char* send, uint16_t timeout) { 01182 flushInput(); 01183 01184 #ifdef ADAFRUIT_FONA_DEBUG 01185 printf("\t---> %s\r\n", send); 01186 #endif 01187 01188 mySerial.printf("%s\r\n",send); 01189 01190 uint8_t l = readline(timeout); 01191 #ifdef ADAFRUIT_FONA_DEBUG 01192 printf("\t<--- %s\r\n", replybuffer); 01193 #endif 01194 return l; 01195 } 01196 01197 // Send prefix, suffix, and newline. Return response (and also set replybuffer with response). 01198 uint8_t Adafruit_FONA::getReply(const char* prefix, char* suffix, uint16_t timeout) { 01199 flushInput(); 01200 01201 #ifdef ADAFRUIT_FONA_DEBUG 01202 printf("\t---> %s%s\r\n", prefix, suffix); 01203 #endif 01204 01205 mySerial.printf("%s%s\r\n", prefix, suffix); 01206 01207 uint8_t l = readline(timeout); 01208 #ifdef ADAFRUIT_FONA_DEBUG 01209 printf("\t<--- %s\r\n", replybuffer); 01210 #endif 01211 return l; 01212 } 01213 01214 // Send prefix, suffix, and newline. Return response (and also set replybuffer with response). 01215 uint8_t Adafruit_FONA::getReply(const char* prefix, int32_t suffix, uint16_t timeout) { 01216 flushInput(); 01217 01218 #ifdef ADAFRUIT_FONA_DEBUG 01219 printf("\t---> %s%d\r\n", prefix, suffix); 01220 #endif 01221 01222 mySerial.printf("%s%d\r\n", prefix, suffix); 01223 01224 uint8_t l = readline(timeout); 01225 #ifdef ADAFRUIT_FONA_DEBUG 01226 printf("\t<--- %s\r\n", replybuffer); 01227 #endif 01228 return l; 01229 } 01230 01231 // Send prefix, suffix, suffix2, and newline. Return response (and also set replybuffer with response). 01232 uint8_t Adafruit_FONA::getReply(const char* prefix, int32_t suffix1, int32_t suffix2, uint16_t timeout) { 01233 flushInput(); 01234 01235 #ifdef ADAFRUIT_FONA_DEBUG 01236 printf("\t---> %s%d,%d\r\n", prefix, suffix1, suffix2); 01237 #endif 01238 01239 mySerial.printf("%s%d,%d\r\n", prefix, suffix1, suffix2); 01240 01241 uint8_t l = readline(timeout); 01242 #ifdef ADAFRUIT_FONA_DEBUG 01243 printf("\t<--- %s\r\n", replybuffer); 01244 #endif 01245 return l; 01246 } 01247 01248 // Send prefix, ", suffix, ", and newline. Return response (and also set replybuffer with response). 01249 uint8_t Adafruit_FONA::getReplyQuoted(const char* prefix, const char* suffix, uint16_t timeout) { 01250 flushInput(); 01251 01252 #ifdef ADAFRUIT_FONA_DEBUG 01253 printf("\t---> %s\"%s\"\r\n", prefix, suffix); 01254 #endif 01255 01256 mySerial.printf("%s\"%s\"\r\n", prefix, suffix); 01257 01258 uint8_t l = readline(timeout); 01259 #ifdef ADAFRUIT_FONA_DEBUG 01260 printf("\t<--- %s\r\n", replybuffer); 01261 #endif 01262 return l; 01263 } 01264 01265 01266 bool Adafruit_FONA::sendCheckReply(const char *send, const char *reply, uint16_t timeout) { 01267 getReply(send, timeout); 01268 01269 return (strcmp(replybuffer, reply) == 0); 01270 } 01271 01272 // Send prefix, suffix, and newline. Verify FONA response matches reply parameter. 01273 bool Adafruit_FONA::sendCheckReply(const char* prefix, char *suffix, const char* reply, uint16_t timeout) { 01274 getReply(prefix, suffix, timeout); 01275 return (strcmp(replybuffer, reply) == 0); 01276 } 01277 01278 // Send prefix, suffix, and newline. Verify FONA response matches reply parameter. 01279 bool Adafruit_FONA::sendCheckReply(const char* prefix, int32_t suffix, const char* reply, uint16_t timeout) { 01280 getReply(prefix, suffix, timeout); 01281 return (strcmp(replybuffer, reply) == 0); 01282 } 01283 01284 // Send prefix, suffix, suffix2, and newline. Verify FONA response matches reply parameter. 01285 bool Adafruit_FONA::sendCheckReply(const char* prefix, int32_t suffix1, int32_t suffix2, const char* reply, uint16_t timeout) { 01286 getReply(prefix, suffix1, suffix2, timeout); 01287 return (strcmp(replybuffer, reply) == 0); 01288 } 01289 01290 // Send prefix, ", suffix, ", and newline. Verify FONA response matches reply parameter. 01291 bool Adafruit_FONA::sendCheckReplyQuoted(const char* prefix, const char* suffix, const char* reply, uint16_t timeout) { 01292 getReplyQuoted(prefix, suffix, timeout); 01293 return (strcmp(replybuffer, reply) == 0); 01294 } 01295 01296 bool Adafruit_FONA::parseReply(const char* toreply, uint16_t *v, char divider, uint8_t index) { 01297 char *p = strstr(replybuffer, toreply); // get the pointer to the voltage 01298 if (p == 0) return false; 01299 p += strlen(toreply); 01300 01301 for (uint8_t i=0; i<index;i++) { 01302 // increment dividers 01303 p = strchr(p, divider); 01304 if (!p) return false; 01305 p++; 01306 } 01307 01308 *v = atoi(p); 01309 01310 return true; 01311 } 01312 01313 bool Adafruit_FONA::parseReply(const char* toreply, char *v, char divider, uint8_t index) { 01314 uint8_t i=0; 01315 char *p = strstr(replybuffer, toreply); 01316 if (p == 0) return false; 01317 p+=strlen(toreply); 01318 01319 for (i=0; i<index;i++) { 01320 // increment dividers 01321 p = strchr(p, divider); 01322 if (!p) return false; 01323 p++; 01324 } 01325 01326 for(i=0; i<strlen(p);i++) { 01327 if(p[i] == divider) 01328 break; 01329 v[i] = p[i]; 01330 } 01331 01332 v[i] = '\0'; 01333 01334 return true; 01335 } 01336 01337 // Parse a quoted string in the response fields and copy its value (without quotes) 01338 // to the specified character array (v). Only up to maxlen characters are copied 01339 // into the result buffer, so make sure to pass a large enough buffer to handle the 01340 // response. 01341 bool Adafruit_FONA::parseReplyQuoted(const char* toreply, char* v, int maxlen, char divider, uint8_t index) { 01342 uint8_t i=0, j; 01343 // Verify response starts with toreply. 01344 char *p = strstr(replybuffer, toreply); 01345 if (p == 0) return false; 01346 p+=strlen(toreply); 01347 01348 // Find location of desired response field. 01349 for (i=0; i<index;i++) { 01350 // increment dividers 01351 p = strchr(p, divider); 01352 if (!p) return false; 01353 p++; 01354 } 01355 01356 // Copy characters from response field into result string. 01357 for(i=0, j=0; j<maxlen && i<strlen(p); ++i) { 01358 // Stop if a divier is found. 01359 if(p[i] == divider) 01360 break; 01361 // Skip any quotation marks. 01362 else if(p[i] == '"') 01363 continue; 01364 v[j++] = p[i]; 01365 } 01366 01367 // Add a null terminator if result string buffer was not filled. 01368 if (j < maxlen) 01369 v[j] = '\0'; 01370 01371 return true; 01372 } 01373 01374 bool Adafruit_FONA::sendParseReply(const char* tosend, const char* toreply, uint16_t *v, char divider, uint8_t index) { 01375 getReply(tosend); 01376 01377 if (! parseReply(toreply, v, divider, index)) return false; 01378 01379 readline(); // eat 'OK' 01380 01381 return true; 01382 }
Generated on Thu Jul 14 2022 05:05:19 by
1.7.2
