Пример #1
0
bool CardReader::findGeneratedBy(char* buf, char* genBy) {
  // Slic3r & S3D
  const char* generatedByString = PSTR("generated by ");
  char* pos = strstr_P(buf, generatedByString);
  if (pos) {
    pos += strlen_P(generatedByString);
    size_t i = 0;
    while (i < GENBY_SIZE - 1 && *pos >= ' ') {
      char c = *pos++;
      if (c == '"' || c == '\\') {
        // Need to escape the quote-mark for JSON
        if (i > GENBY_SIZE - 3) break;
        genBy[i++] = '\\';
      }
      genBy[i++] = c;
    }
    genBy[i] = 0;
    return true;
  }

  // CURA
  const char* slicedAtString = PSTR(";Sliced at: ");
  pos = strstr_P(buf, slicedAtString);
  if (pos) {
    strcpy_P(genBy, PSTR("Cura"));
    return true;
  }

  // UNKNOWN
  strcpy_P(genBy, PSTR("Unknown"));
  return false;
}
Пример #2
0
bool CardReader::findLayerHeight(char* buf, float& layerHeight) {
  // SLIC3R
  layerHeight = 0;
  const char* layerHeightSlic3r = PSTR("; layer_height ");
  char *pos = strstr_P(buf, layerHeightSlic3r);
  if (pos) {
    pos += strlen_P(layerHeightSlic3r);
    while (*pos == ' ' || *pos == 't' || *pos == '=' || *pos == ':') {
      ++pos;
    }
    layerHeight = strtod(pos, NULL);
    return true;
  }

  // CURA
  const char* layerHeightCura = PSTR("Layer height: ");
  pos = strstr_P(buf, layerHeightCura);
  if (pos) {
    pos += strlen_P(layerHeightCura);
    while (*pos == ' ' || *pos == 't' || *pos == '=' || *pos == ':') {
      ++pos;
    }
    layerHeight = strtod(pos, NULL);
    return true;
  }

  return false;
}
Пример #3
0
byte Dreambox_ParsePayloadLine(void)
{
//<?xml version="1.0" encoding="UTF-8"?>
	// check end of XML header line and remove the entire line from the buffer
	char * p = strstr_P(s_buf, PSTR("?>"));
	if ( p>0 ) {
		p += 2; // set pointer to the string to copy
		if ( *p==0 )	s_ind = 0;	// set pointer to the beginning of the buffer
		else {
			strcpy(s_buf, p);
			s_ind -= (p - s_buf);	// update index
		}
		Serial.println(F("DM parsed payload line: XML header removed."));
	} else {
	// parse here the data dependent on the command
		switch ( dm_cmd ) {
			case CMD_TIMER_LIST:
/* reply:
<e2timerlist>
</e2timerlist>
*/
				if ( strstr_P(s_buf, PSTR("</e2timerlist>")) ) {
					reply |= END;
					return 1;	// flush any further data
				}
				p = strstr_P(s_buf, PSTR("<e2timerlist>"));
				if ( p>0 ) {
					reply |= START;
					// remove all data before this xml tag from buffer
					p += 13; // set pointer to the end of this tag
					if ( *p==0 )	s_ind = 0;	// set pointer to the beginning of the buffer
					else {
						strcpy(s_buf, p);
						s_ind -= (p - s_buf);	// update index
					}
				}
				if ( (reply & START) && strlen(s_buf)>0 ) {
					reply |= DATA;
					return 1;	// flush any further data
				}
				break;
			case CMD_TIMER_CLEANUP:
/* reply:
<?xml version="1.0" encoding="UTF-8"?>
<e2simplexmlresult>
	<e2state>True</e2state>
	<e2statetext>List of Timers has been cleaned</e2statetext>	
</e2simplexmlresult>
*/
				break;
			case CMD_GET_STATUS:
				break;
		}
	}
	return 0;
}
Пример #4
0
void HTTPRequestParser::parse (char *request) {
	char *p, *q;

#ifdef VERBOSE_REQUEST_PARSER
	DPRINT (F("Parsing request: \""));
	DPRINT (request);
	DPRINTLN (F("\""));
#endif

	url[0] = '\0';
	if ((p = strstr_P (request, PSTR ("GET ")))) {
		if ((q = strchr (p + 4,  ' ')))
			strlcpy (url, p + 4, q - p - 4 + 1 < MAX_URL_LEN ? q - p - 4 + 1 : MAX_URL_LEN);
		else
			strlcpy (url, p + 4, MAX_URL_LEN);

#ifdef VERBOSE_REQUEST_PARSER
		DPRINT (F("Extracted URL: \""));
		DPRINT (url);
		DPRINTLN (F("\""));
#endif
	} else {
		DPRINTLN (F("Cannot extract URL"));
	}
}
Пример #5
0
uint8_t ATEasySMS::readNextIdxSMS()
{
    snprintf_P(m_cmdBuffer, ATDEV_BUFF_CMD_SIZE, ATDEV_CMD_CMGL, ATDEV_OPT_CMGL_ALL);

    // Prepare answer end
    m_endBuffer[0] = ATDEV_CH_LF;
    m_endBuffer[1] = 0x00;

    // Send command
    this->sendATCmd(true);

    // Flush
    while (m_hwSerial->read() >= 0);

    // check answer / +CMGL: 
    if (strstr_P(m_msgBuffer, ATDEV_STR_CMGL) != NULL) {

        // parse
        if (this->parseInternalData() > 1) {
            return atoi(this->getParseElement(1));
        }
    }

    return ATDEV_SMS_NO_MSG;
}
Пример #6
0
static void
soap_parse_element (soap_context_t *ctx)
{
  if (*ctx->buf != '<')
    SOAP_STREAM_ERROR();

  if (ctx->buf[1] == '?')
    return;			/* ignore parser instruction. */

  if (ctx->parsing_complete)
    return;

  ctx->buf[ctx->buflen] = 0;
  SOAP_DEBUG ("parse_element %s\n", ctx->buf);
  if (!ctx->found_envelope)
    {
      if (strncmp_P (ctx->buf + 1, PSTR("Envelope"), 8))
	SOAP_STREAM_ERROR();
      ctx->found_envelope = 1;
    }

  else if (!ctx->found_body)
    {
      if (strncmp_P (ctx->buf + 1, PSTR("Body"), 4))
	return;			/* ignore anything until <Body> */
      ctx->found_body = 1;
    }
  else if (!ctx->found_funcname)
    {
      soap_lookup_funcname (ctx);
      ctx->found_funcname = 1;
    }
  else if (strncmp_P (ctx->buf + 1, PSTR("/Body"), 5) == 0)
    {
      ctx->parsing_complete = 1;
    }
  else if (ctx->buf[1] != '/' && ctx->argslen < SOAP_MAXARGS)
    {
      char *ptr = strstr_P (ctx->buf + 1, PSTR("type="));
      if (!ptr)
	SOAP_STREAM_ERROR ();

      ptr += 6;			/* Skip type=" */
      char *end = strchr (ptr, '"');
      if (!end)
	SOAP_STREAM_ERROR ();
      *end = 0;			/* chop off rest beyond type specifier */

      end = strchr (ptr, ':');
      if (end) ptr = end + 1;	/* Ignore namespace specifier */

      SOAP_DEBUG ("found arg type: '%s'\n", ptr);
      if (strcmp_P (ptr, PSTR("int")) == 0)
	ctx->args[ctx->argslen].type = SOAP_TYPE_INT;
      else if (strcmp_P (ptr, PSTR("string")) == 0)
	ctx->args[ctx->argslen].type = SOAP_TYPE_STRING;
      else
	SOAP_STREAM_ERROR ();
    }
}
ConnectionStatus_t SIM900GPRS::parseConnectionStatus(char * str)
{
#ifdef DEBUG
    char outputStr[40];
    _debug->print(millis());
    _debug->print(F(" Parse status: "));
    _debug->println(str);
#endif
    int i = 0;
    int max = sizeof(connectionStatusStrings)/sizeof(*connectionStatusStrings);
#ifdef DEBUG
    _debug->print(millis());
    _debug->print(F(" max: "));
    _debug->println(max);
#endif
#ifdef DEBUG
    strcpy_P(outputStr, (char*)pgm_read_word(&(connectionStatusStrings[i])));
    _debug->print(millis());
    _debug->print(F(" check for: "));
    _debug->println(outputStr);
#endif
    while( (NULL == strstr_P(str, (char*)pgm_read_word(&(connectionStatusStrings[i])))) && (i<max) ) {
        i++;
#ifdef DEBUG
        strcpy_P(outputStr, (char*)pgm_read_word(&(connectionStatusStrings[i])));
        _debug->print(millis());
        _debug->print(F(" check for: "));
        _debug->println(outputStr);
#endif
    }
    return (ConnectionStatus_t)i;
}
Пример #8
0
static void copyUptoLinefeed(const char *startFrom, char *writeTo)
{
    uint8_t newLength = strstr_P(startFrom, rn) - startFrom;
    assert(newLength);
    assert(writeTo);
    memcpy(writeTo, startFrom, newLength);
}
// Parse a quoted string in the response fields and copy its value (without quotes)
// to the specified character array (v).  Only up to maxlen characters are copied
// into the result buffer, so make sure to pass a large enough buffer to handle the
// response.
boolean Adafruit_FONA::parseReplyQuoted(const __FlashStringHelper *toreply,
          char *v, int maxlen, char divider, uint8_t index) {
  uint8_t i=0, j;
  // Verify response starts with toreply.
  char *p = strstr_P(replybuffer, (prog_char*)toreply);
  if (p == 0) return false;
  p+=strlen_P((prog_char*)toreply);

  // Find location of desired response field.
  for (i=0; i<index;i++) {
    // increment dividers
    p = strchr(p, divider);
    if (!p) return false;
    p++;
  }

  // Copy characters from response field into result string.
  for(i=0, j=0; j<maxlen && i<strlen(p); ++i) {
    // Stop if a divier is found.
    if(p[i] == divider)
      break;
    // Skip any quotation marks.
    else if(p[i] == '"')
      continue;
    v[j++] = p[i];
  }

  // Add a null terminator if result string buffer was not filled.
  if (j < maxlen)
    v[j] = '\0';

  return true;
}
Пример #10
0
void ATDev::trimATEnd(char* readBuf, uint16_t readBufSize, uint16_t dataSize)
{
    bool        foundAT = false;
    uint16_t    pos     = dataSize -2;

    // secure check
    if (pos < 0) {
        return;
    }

    // Search OK AT Answer String
    for ( ; pos > 0; --pos) {
        if (strstr_P(readBuf + pos, ATDEV_END_OK) != NULL) {
            --pos;
            foundAT = true;
            break;
        }
    }

    // NO AT CMD found!
    if (!foundAT) {
        return;
    }

    // find next character they not for AT communication
    for ( ; pos > 0; --pos) {
        if (readBuf[pos] != ATDEV_CH_CR && readBuf[pos] != ATDEV_CH_LF) {
            break;
        }
    }

    // clean AT communication controll characters
    memset(readBuf + pos +1, 0x00, readBufSize - pos -1);
}
Пример #11
0
size_t GPRSClient::callback(byte *buf, size_t length, void *data) {
	size_t used = 0;
	GPRSClient *client = (GPRSClient *)data;
	if (client->_size_left == 0) {
		char *p = strstr_P((char *)buf, G("+IPD"));
		if (p) {
			p += 4;
			char *end = strchr(p, ':');
			if (end) {
				*end = 0;
				client->_size_left = atoi(p);
				used = (byte *)end - buf + 1;
			}
		}
	}
	while (client->_size_left > 0 && used < length) {
		// Data will be discarded when buffer is full
		if (!client->isFull()) {
			client->_rx_buf[client->_rx_tail] = buf[used++];
			client->_rx_tail = nextIndex(client->_rx_tail);
		}
		client->_size_left--;
	}
	return used + client->_size_left;
}
uint8_t Adafruit_FONA::getGPS(uint8_t arg, char *buffer, uint8_t maxbuff) {
  int32_t x = arg;

  if ( (_type == FONA3G_A) || (_type == FONA3G_E) ) {
    getReply(F("AT+CGPSINFO"));
  } else if (_type == FONA808_V1) {
    getReply(F("AT+CGPSINF="), x);
  } else {
    getReply(F("AT+CGNSINF"));
  }

  char *p = strstr_P(replybuffer, (prog_char*)F("SINF"));
  if (p == 0) {
    buffer[0] = 0;
    return 0;
  }

  p+=6;

  uint8_t len = max(maxbuff-1, strlen(p));
  strncpy(buffer, p, len);
  buffer[len] = 0;

  readline(); // eat 'OK'
  return len;
}
Пример #13
0
/* Copy ID from incoming <iq type='get'> message to our STATE. */
static uint8_t
jabber_extract_id (void)
{
    char *idptr = strstr_P (uip_appdata, PSTR ("id='"));
    if (idptr) {
	idptr += 4;
	JABDEBUG ("id=' found %i \n", idptr);

	char *idendptr = strchr (idptr, '\'');
	if (idendptr) {
	    uint8_t idlength = idendptr - idptr;

	    if (idlength > 15)
		JABDEBUG ("id too long: %i \n", idlength);

	    else {
		JABDEBUG ("endquote found %i \n", idendptr);
		memmove (STATE->actionid, idptr, idlength);
		STATE->actionid[idlength] = 0;
		JABDEBUG ("given id: %s\n", STATE->actionid);
	    }
	}

	return 0;
    }
    else
	return 1;		/* Failed. */
}
Пример #14
0
uint16_t readHttpFrame(EthernetClient client) {
	uint16_t size = 0;

    size = client.read((uint8_t *) buf, BUFFER_SIZE);
    buf[size] = 0;

    char *found = strstr_P((char *) buf, PSTR("Content-Length: "));
    if (found == 0) {
        return size; // no length so we stop here
    }
    int contentLength = atoi(&found[16]);
    size_t contentPos = strlen(&strstr_P(found, DOUBLE_ENDL)[4]);
    if (contentPos < contentLength) {
        size += client.read((uint8_t *) &buf[size], contentLength - contentPos);
    }
	return size;
}
Пример #15
0
int SimGSM::recvUntil_P(const char *s1, const char *s2, const char *s3) {
	const char *ss[3] = { s1, s2, s3 };
	recv();
	for (int i = 0; i < 3; i++)
		if (ss[i] && strstr_P((char *)_buf, ss[i]) != NULL)
			return i + 1;
	return 0;
}
Пример #16
0
 inline
 size_t
 find_P(PGM_P str) {
     char * match = strstr_P(c_str(), str);
     if (match) {
         return match - begin();
     }
     return npos;
 }
Пример #17
0
bool ATSMS::isCMSError()
{
    // found "+CMS ERROR: %d"
    if (strstr_P(m_msgBuffer, ATDEV_STR_CMS) != NULL) {
        return true;
    }

    return false;
}
Пример #18
0
boolean GPRSClient::attach() {
	if (!_gsm->isRegistered() || !_gsm->isAttached())
		return false;

	char cmd[80];
	getStatus(cmd, sizeof(cmd));

	// If state is in "CONNECT OK", "TCP CONNECTING", "UDP CONNECTING", close it.
	// We use "CONNECT" as a shortcut to save space
	if (strstr_P(cmd, G("CONNECT"))) {
		// We shouldn't be here normally, but this can happen when hot resetting device
		_connected = true;
		stop();
		getStatus(cmd, sizeof(cmd));
	}

	if (!strcmp_P(cmd, G("IP CLOSE")))
		return true;

	if (!strcmp_P(cmd, G("PDP DEACT")))
		_gsm->sendRecvUntil_P(G("AT+CIPSHUT"), CLOSE_TIMEOUT, G("SHUT OK"), G("ERROR"));

	// State 0: IP INITIAL
	if (!strcmp_P(cmd, G("IP INITIAL"))) {
		char fmt[25];
		strcpy_P(fmt, G("AT+CSTT=\"%s\",\"%s\",\"%s\""));
		snprintf(cmd, sizeof(cmd), fmt, _apn, _user, _pass);
		_gsm->send(cmd);
		if (!_gsm->recvUntil_P(G("OK")))
			return false;
		getStatus(cmd, sizeof(cmd));
	}

	// State 1: IP START
	if (!strcmp_P(cmd, G("IP START"))) {
		_gsm->send_P(G("AT+CIICR"));
		if (_gsm->recvUntil_P(CIICR_TIMEOUT, G("OK"), G("ERROR")) != 1)
			return false;
		getStatus(cmd, sizeof(cmd));
	}

	// State 2: IP CONFIG
	while (!strcmp_P(cmd, G("IP CONFIG"))) {
		delay(1000);
		getStatus(cmd, sizeof(cmd));
	}

	// State 3: IP GPRSACT
	if (!strcmp_P(cmd, G("IP GPRSACT"))) {
		if (!_gsm->sendRecvUntil_P(G("AT+CIFSR"), G(".")))
			return false;
		getStatus(cmd, sizeof(cmd));
	}

	return !strcmp_P(cmd, G("IP STATUS"));
}
Пример #19
0
uint16_t ATSMS::readNextIdxSMS(uint16_t lastIdx)
{
    uint16_t nextIdx = ATDEV_SMS_NO_MSG;

    // AT cmd
    snprintf_P(m_cmdBuffer, ATDEV_BUFF_CMD_SIZE, ATDEV_CMD_CMGL, ATDEV_OPT_CMGL_ALL);

    do {
        // Set +CMGL: as end
        this->setCMGLEndBuffer();

        // check answer / +CMGL: 
        if (this->sendATCmdStream() == ATDEV_OK && this->readLine() == ATDEV_OK) {

            // is state not REC UNREAD or REC READ
            if (strstr_P(m_msgBuffer, ATDEV_OPT_CMGL_READ) == NULL &&
                strstr_P(m_msgBuffer, ATDEV_OPT_CMGL_UNREAD) == NULL) {
                continue;
            }

            // parse
            if (this->parseInternalData() >= 0) {
                nextIdx = atoi(this->getParseElement(0));
            }
            else {
                nextIdx = ATDEV_SMS_NO_MSG;
                break;
            }
        }
        // error
        else {
            nextIdx = ATDEV_SMS_NO_MSG;
            break;
        }

    } while ((nextIdx < lastIdx && !(nextIdx == 0 && lastIdx == 0)) || nextIdx == ATDEV_SMS_NO_MSG);

    // flush other
    this->flushInput();

    return nextIdx;
}
Пример #20
0
static uint8_t
jabber_extract_from(void)
{
  const char *from = strstr_P(uip_appdata, PSTR("from="));
  if (!from)
    return 1;

  from += 6;                    /* skip from=' */

  const char *resource_end = strchr(from, '/');
  if (!resource_end)
  {
    JABDEBUG("from addr resource not found\n");
    return 1;
  }

  const char *endptr = strchr(from, '\'');
  if (!endptr)
    endptr = strchr(from, '\"');
  if (!endptr)
  {
    JABDEBUG("end of from addr not found\n");
    return 1;
  }

  uint8_t jid_len = resource_end - from;
  uint8_t len = endptr - from;
  if (len + 1 > TARGET_BUDDY_MAXLEN)
  {
    JABDEBUG("extract_from: from addr too long\n");
    return 1;
  }

  uint8_t auth = 1;
  for (uint8_t i = 0;
       i < (sizeof(jabber_known_buddies) / sizeof(jabber_known_buddies[0]));
       ++i)
  {
    char *jidlist_ptr = (char *) pgm_read_word(&jabber_known_buddies[i]);
    auth = strncmp_P(from, jidlist_ptr, jid_len) == 0;
    if (auth == 1)
      break;
  }

  JABDEBUG("authentificated %s: %d\n", from, auth);
  if (!auth)
    return 2;                   /* Permission denied. */

  memmove(STATE->target, from, len);
  STATE->target[len] = 0;

  JABDEBUG("message from: %s\n", STATE->target);
  return 0;                     /* Looks good. */
}
Пример #21
0
static char *get_upto_linefeed(const char *start_from) {
    char    *write_to;
    uint8_t new_length = strstr_P(start_from, rn) - start_from + 1;

    assert(new_length);
    write_to = (char *)malloc(new_length);     //+1 for '\x00'
    assert(write_to);
    memcpy(write_to, start_from, new_length - 1);
    write_to[new_length - 1] = 0;

    return write_to;
}
Пример #22
0
static char* getUptoLinefeed(const char *startFrom)
{
    char *write_to = NULL;
    uint8_t new_length = strstr_P(startFrom, rn) - startFrom;
    assert(new_length);
    write_to = (char *)malloc(new_length+1); //+1 for '\x00'
    assert(write_to);
    memcpy(write_to, startFrom, new_length);
    write_to[ new_length ] = 0;

    return write_to;
}
int8_t Adafruit_FONA::GPSstatus(void) {
  if (_type == FONA808_V2) {
    // 808 V2 uses GNS commands and doesn't have an explicit 2D/3D fix status.
    // Instead just look for a fix and if found assume it's a 3D fix.
    getReply(F("AT+CGNSINF"));
    char *p = strstr_P(replybuffer, (prog_char*)F("+CGNSINF: "));
    if (p == 0) return -1;
    p+=12; // Skip to second value, fix status.
    readline(); // eat 'OK'
    //Serial.println(p);
    // Assume if the fix status is '1' then we have a 3D fix, otherwise no fix.
    if (p[0] == '1') return 3;
    else return 0;
  }
  if (_type == FONA3G_A || _type == FONA3G_E) {
    // FONA 3G doesn't have an explicit 2D/3D fix status.
    // Instead just look for a fix and if found assume it's a 3D fix.
    getReply(F("AT+CGPSINFO"));
    char *p = strstr_P(replybuffer, (prog_char*)F("+CGPSINFO:"));
    if (p == 0) return -1;
    if (p[10] != ',') return 3; // if you get anything, its 3D fix
    return 0;
  }
  else {
    // 808 V1 looks for specific 2D or 3D fix state.
    getReply(F("AT+CGPSSTATUS?"));
    char *p = strstr_P(replybuffer, (prog_char*)F("SSTATUS: Location "));
    if (p == 0) return -1;
    p+=18;
    readline(); // eat 'OK'
    //Serial.println(p);
    if (p[0] == 'U') return 0;
    if (p[0] == 'N') return 1;
    if (p[0] == '2') return 2;
    if (p[0] == '3') return 3;
  }
  // else
  return 0;
}
/* Parses the input buffer looking for this command string */
boolean GetBatteryLoadCommand::parse(byte * buffer, int size) {
	//set a bound to the buffer 
	buffer[size - 1] = 0;
	char * _b = (char *)buffer;

	if (strchr(_b, 10) != NULL) {
		if (strstr_P(_b, (const char *)F("GET BATTERY LOAD")) != NULL) {
			return true;
		}
	}

	return false;
}
Пример #25
0
static unsigned short function_config(char* buffer, char* parameters) {
    // find the settings in parameters and parse them
    char* position;
    int value;
    position=strstr_P(parameters,dhcp);
    if (position!=NULL) {
        value=atoi(position+sizeof(dhcp)-1);
        config.dhcpenable=value;
    }
    position=strstr_P(parameters,ip);
    if (position!=NULL) {
        parse_ip_address(config.ipaddr,position+sizeof(ip)-1);
        uip_sethostaddr(&config.ipaddr);
    }
    position=strstr_P(parameters,mask);
    if (position!=NULL) {
        parse_ip_address(config.netmask,position+sizeof(mask)-1);
        uip_setnetmask(&config.netmask);
    }
    position=strstr_P(parameters,gw);
    if (position!=NULL) {
        parse_ip_address(config.gateway,position+sizeof(gw)-1);
        uip_setdraddr(&config.gateway);
    }
    position=strstr_P(parameters,auth);
    if (position!=NULL) {
        char* param=position+sizeof(auth)-1;
        url_decode(param);
        // copy the parameter to the config
        strcpy(config.authentication,param);
    }
    writeFlashConfig();
    // return a dummy because a null string is not allowed
    buffer[0]=' ';
    buffer[1]=0;
    return 1;
}
/**
 *
 * Parameters -
 * Returns -
 */
char* SIM900GPRS::getTimeStr()
{
#ifdef DEBUG
    _debug->print(millis());
    _debug->println(F(" AT+CCLK?"));
#endif
    _cell->println(F("AT+CCLK?")); // RETURNS: +CCLK: "15/03/26,17:25:28+04"
    if(!successfulResponse()) { // no response
        return NULL;
    }
    char* end = strstr_P(_buffer, PSTR("OK"));
    end -=8; // end points att O in OK and is preceeded with two \r\n and a +zz"
    end[0] = 0;
    return &_buffer[10]; // start from character after first "
}
// Connect to WiFi access point.  SSID and password are flash-resident
// strings.  May take several seconds to execute, this is normal.
// Returns true on successful connection, false otherwise.
boolean Adafruit_ESP8266::connectToAP(Fstr *ssid, Fstr *pass) {
  char buf[256];

  println(F("AT+CWMODE=1")); // WiFi mode = Sta
  readLine(buf, sizeof(buf));
  if(!(strstr_P(buf, (Pchr *)F("OK")) ||
       strstr_P(buf, (Pchr *)F("no change")))) return false;

  print(F("AT+CWJAP=\"")); // Join access point
  print(ssid);
  print(F("\",\""));
  print(pass);
  println('\"');
  uint32_t save = receiveTimeout;  // Temporarily override recv timeout,
  receiveTimeout = connectTimeout; // connection time is much longer!
  boolean found = find();          // Await 'OK' message
  receiveTimeout = save;           // Restore normal receive timeout
  if(found) {
    println(F("AT+CIPMUX=0"));     // Set single-client mode
    found = find();                // Await 'OK'
  }

  return found;
}
/**
 * Obtain modem IMEI (command AT)
 * Returns - string with modem IMEI number or NULL if failed
 * The IMEI string is on the format "AABBBBBBCCCCCCEE" and always 16 characters long.
 */
char* SIM900GPRS::getIMEI()
{
#ifdef DEBUG
    _debug->print(millis());
    _debug->println(F(" AT+GSN"));
#endif
    _cell->println(F("AT+GSN")); //RETURNS: 0000646714 OK
    if(!successfulResponse()) { // no response
        return NULL;
    }
    char* end = strstr_P(_buffer, PSTR("OK"));
    end -=4; // end points att O in OK and is preceeded with \r\n
    end[0] = 0;
    return _buffer+2;
}
char* SIM900GPRS::getSoftwareVersion() {
    //
#ifdef DEBUG
    _debug->print(millis());
    _debug->println(F(" AT+CGMR"));
#endif
    _cell->println(F("AT+CGMR")); // Retrurns: Revision:1137B11SIM900M64_ST
    if(!successfulResponse()) { // no response
        return NULL;
    }
    char* end = strstr_P(_buffer, PSTR("OK"));
    end -=4; // end points att O in OK and is preceeded with two times '\r\n'
    end[0] = 0;
    return &_buffer[11]; // start from first character after '\r\nRevision:'
}
boolean Adafruit_FONA_3G::parseReply(const __FlashStringHelper *toreply,
          float *f, char divider, uint8_t index) {
  char *p = strstr_P(replybuffer, (prog_char*)toreply);  // get the pointer to the voltage
  if (p == 0) return false;
  p+=strlen_P((prog_char*)toreply);
  //Serial.println(p);
  for (uint8_t i=0; i<index;i++) {
    // increment dividers
    p = strchr(p, divider);
    if (!p) return false;
    p++;
    //Serial.println(p);

  }
  *f = atof(p);

  return true;
}