Teensy 3.1 with SIM908 breakout

Status
Not open for further replies.

Fyod

Well-known member
Hey guys!
I'm using my Teensy to control a SIM908 breakout. Pretty straightforward, but I have one problem.
Everything is working pretty fine with the GSM library made for the breakout (www.gsmlib.org), except when I try to send HTTP posts, they are sent about every 30 seconds. I would like to get a post every 3 to 5 seconds.
I made a simple PHP page that then sends the data to a SQL db. When I try it in a PC browser, I can "post" as often as I like.
I've tried fiddling around with the delays, to no avail, althou in SerialMonitor, I do get the answer more often, not the actual post though.
According to the SQL entries, they happen exactly every 29 or 30 seconds.

Anyone have any ideas what could be holding them up?

Here's the code I think is delaying the posts.

Code:
#include "inetGSM.h"
#define _GSM_CONNECTION_TOUT_ 5
#define _TCP_CONNECTION_TOUT_ 20
#define _GSM_DATA_TOUT_ 10

int InetGSM::httpGET(const char* server, int port, const char* path, char* result, int resultlength)
{
  boolean connected=false;
  int n_of_at=0;
  int length_write;
  char end_c[2];
  end_c[0]=0x1a;
  end_c[1]='\0';

  /*
  Status = ATTACHED.
  if(gsm.getStatus()!=GSM::ATTACHED)
    return 0;
  */
  while(n_of_at<3){
	  if(!connectTCP(server, port)){
	  	#ifdef DEBUG_ON
			Serial.println("DB:NOT CONN");
		#endif	
	    	n_of_at++;
	  }
	  else{
		connected=true;
		n_of_at=3;
	}
  }

  if(!connected) return 0;
	
  gsm.SimpleWrite("GET ");
  gsm.SimpleWrite(path);
  gsm.SimpleWrite(" HTTP/1.0\nHost: ");
  gsm.SimpleWrite(server);
  gsm.SimpleWrite("\n");
  gsm.SimpleWrite("User-Agent: Arduino");
  gsm.SimpleWrite("\n\n");
  gsm.SimpleWrite(end_c);

  switch(gsm.WaitResp(10000, 10, "SEND OK")){
	case RX_TMOUT_ERR: 
		return 0;
	break;
	case RX_FINISHED_STR_NOT_RECV: 
		return 0; 
	break;
  }
  
  
 delay(50);
  	#ifdef DEBUG_ON
		Serial.println("DB:SENT");
	#endif	
  int res= gsm.read(result, resultlength);

  //gsm.disconnectTCP();
  
  //int res=1;
  return res;
}

int InetGSM::httpPOST(const char* server, int port, const char* path, const char* parameters, char* result, int resultlength)
{
  boolean connected=false;
  int n_of_at=0;
  char itoaBuffer[8];
  int num_char;
  char end_c[2];
  end_c[0]=0x1a;
  end_c[1]='\0';

  while(n_of_at<3){
	  if(!connectTCP(server, port)){
	  	#ifdef DEBUG_ON
			Serial.println("DB:NOT CONN");
		#endif	
	    	n_of_at++;
	  }
	  else{
		connected=true;
		n_of_at=3;
	}
  }

  if(!connected) return 0;
	
  gsm.SimpleWrite("POST ");
  gsm.SimpleWrite(path);
  gsm.SimpleWrite(" HTTP/1.1\nHost: ");
  gsm.SimpleWrite(server);
  gsm.SimpleWrite("\n");
  gsm.SimpleWrite("User-Agent: Arduino\n");
  gsm.SimpleWrite("Content-Type: application/x-www-form-urlencoded\n");
  gsm.SimpleWrite("Content-Length: ");
  itoa(strlen(parameters),itoaBuffer,10);
  gsm.SimpleWrite(itoaBuffer);
  gsm.SimpleWrite("\n\n");
  gsm.SimpleWrite(parameters);
  gsm.SimpleWrite("\n\n");
  gsm.SimpleWrite(end_c);
 
  switch(gsm.WaitResp(10000, 10, "SEND OK")){
	case RX_TMOUT_ERR: 
		return 0;
	break;
	case RX_FINISHED_STR_NOT_RECV: 
		return 0; 
	break;
  }

 delay(50);
	#ifdef DEBUG_ON
		Serial.println("DB:SENT");
	#endif	

  int res= gsm.read(result, resultlength);
  //gsm.disconnectTCP();
  return res;
}

int InetGSM::openmail(char* server, char* loginbase64, char* passbase64, char* from, char* to, char* subj)
{
  boolean connected=false;
  int n_of_at=0;
  char end_c[2];
  end_c[0]=0x1a;
  end_c[1]='\0';
	
  while(n_of_at<3){
	  if(!connectTCP(server, 25)){
	  	#ifdef DEBUG_ON
			Serial.println("DB:NOT CONN");
		#endif	
	    	n_of_at++;
	  }
	  else{
		connected=true;
		n_of_at=3;
	}
  }

  if(!connected) return 0;  
  
	delay(100);   
    gsm.SimpleWrite("HELO ");  gsm.SimpleWrite(server);  gsm.SimpleWrite("\n");
	gsm.SimpleWrite(end_c);
	gsm.WaitResp(5000, 100, "OK");
	if(!gsm.IsStringReceived("SEND OK"))
		return 0;
    delay(500);
	gsm.WaitResp(5000, 100);
	
	delay(100);   
	gsm.SimpleWriteln("AT+CIPSEND");
	switch(gsm.WaitResp(5000, 200, ">")){
		case RX_TMOUT_ERR: 
			return 0;
			break;
		case RX_FINISHED_STR_NOT_RECV: 
			return 0; 
			break;
	}
    gsm.SimpleWrite("AUTH LOGIN\n");
	gsm.SimpleWrite(end_c);
	gsm.WaitResp(5000, 100, "OK");
	if(!gsm.IsStringReceived("OK"))
		return 0;
    delay(500);
	gsm.WaitResp(5000, 100);
		
	delay(100);   
	gsm.SimpleWriteln("AT+CIPSEND");
	switch(gsm.WaitResp(5000, 200, ">")){
		case RX_TMOUT_ERR: 
			return 0;
			break;
		case RX_FINISHED_STR_NOT_RECV: 
			return 0; 
			break;
	}
    gsm.SimpleWrite(loginbase64);gsm.SimpleWrite("\n");
	gsm.SimpleWrite(end_c);
	gsm.WaitResp(5000, 100, "OK");
	if(!gsm.IsStringReceived("OK"))
		return 0;
    delay(500);
	gsm.WaitResp(5000, 100);

	delay(100);   
	gsm.SimpleWriteln("AT+CIPSEND");
	switch(gsm.WaitResp(5000, 200, ">")){
		case RX_TMOUT_ERR: 
			return 0;
			break;
		case RX_FINISHED_STR_NOT_RECV: 
			return 0; 
			break;
	}	
    gsm.SimpleWrite(passbase64);gsm.SimpleWrite("\n");
	gsm.SimpleWrite(end_c);
	gsm.WaitResp(5000, 100, "OK");
	if(!gsm.IsStringReceived("OK"))
		return 0;
    delay(500);
	gsm.WaitResp(5000, 100);
	

	delay(100);   
	gsm.SimpleWriteln("AT+CIPSEND");
	switch(gsm.WaitResp(5000, 200, ">")){
		case RX_TMOUT_ERR: 
			return 0;
			break;
		case RX_FINISHED_STR_NOT_RECV: 
			return 0; 
			break;
	}
    gsm.SimpleWrite("MAIL From: <");gsm.SimpleWrite(from);gsm.SimpleWrite(">\n");
	gsm.SimpleWrite(end_c);
	gsm.WaitResp(5000, 100, "OK");
	if(!gsm.IsStringReceived("OK"))
		return 0;
    delay(500);
	gsm.WaitResp(5000, 100, "");
	
	delay(100);   
	gsm.SimpleWriteln("AT+CIPSEND");
	switch(gsm.WaitResp(5000, 200, ">")){
		case RX_TMOUT_ERR: 
			return 0;
			break;
		case RX_FINISHED_STR_NOT_RECV: 
			return 0; 
			break;
	}
    gsm.SimpleWrite("RCPT TO: <");gsm.SimpleWrite(to);gsm.SimpleWrite(">\n");
	gsm.SimpleWrite(end_c);
	gsm.WaitResp(5000, 100, "OK");
	if(!gsm.IsStringReceived("OK"))
		return 0;
    delay(500);
	gsm.WaitResp(5000, 100, "");

		delay(100);   
	gsm.SimpleWriteln("AT+CIPSEND");
	switch(gsm.WaitResp(5000, 200, ">")){
		case RX_TMOUT_ERR: 
			return 0;
			break;
		case RX_FINISHED_STR_NOT_RECV: 
			return 0; 
			break;
	}
    gsm.SimpleWrite("Data\n");
	gsm.SimpleWrite(end_c);
	gsm.WaitResp(5000, 100, "OK");
	if(!gsm.IsStringReceived("OK"))
		return 0;
    delay(500);
	gsm.WaitResp(5000, 100, "");

	delay(100);   
	gsm.SimpleWriteln("AT+CIPSEND");
	switch(gsm.WaitResp(5000, 200, ">")){
		case RX_TMOUT_ERR: 
			return 0;
			break;
		case RX_FINISHED_STR_NOT_RECV: 
			return 0; 
			break;
	}
    gsm.SimpleWrite("Subject: ");gsm.SimpleWrite(subj);gsm.SimpleWrite("\n\n");
	
    return 1;
}
int InetGSM::closemail()
{
	char end_c[2];
	end_c[0]=0x1a;
	end_c[1]='\0';
  
	gsm.SimpleWrite("\n.\n");
	gsm.SimpleWrite(end_c);
	disconnectTCP();
	return 1;
}
 

int InetGSM::attachGPRS(char* domain, char* dom1, char* dom2)
{
   int i=0;
   delay(5000);
   
  //gsm._tf.setTimeout(_GSM_DATA_TOUT_);	//Timeout for expecting modem responses.
  gsm.WaitResp(50, 50);
  gsm.SimpleWriteln("AT+CIFSR");
  if(gsm.WaitResp(5000, 50, "ERROR")!=RX_FINISHED_STR_RECV){
  	#ifdef DEBUG_ON
		Serial.println("DB:ALREADY HAVE AN IP");
	#endif
	  gsm.SimpleWriteln("AT+CIPCLOSE");
	gsm.WaitResp(5000, 50, "ERROR");
	delay(2000);
	gsm.SimpleWriteln("AT+CIPSERVER=0");
	gsm.WaitResp(5000, 50, "ERROR");
	return 1;
  }
  else{

	#ifdef DEBUG_ON
		Serial.println("DB:STARTING NEW CONNECTION");
	#endif
  
  gsm.SimpleWriteln("AT+CIPSHUT");
  
  switch(gsm.WaitResp(500, 50, "SHUT OK")){

	case RX_TMOUT_ERR: 
		return 0;
	break;
	case RX_FINISHED_STR_NOT_RECV: 
		return 0; 
	break;
  }
	#ifdef DEBUG_ON
		Serial.println("DB:SHUTTED OK");
	#endif
	 delay(1000);
	 
  gsm.SimpleWrite("AT+CSTT=\"");
  gsm.SimpleWrite(domain);
  gsm.SimpleWrite("\",\"");
  gsm.SimpleWrite(dom1);
  gsm.SimpleWrite("\",\"");
  gsm.SimpleWrite(dom2);
  gsm.SimpleWrite("\"\r");  

  
  switch(gsm.WaitResp(500, 50, "OK")){

	case RX_TMOUT_ERR: 
		return 0;
	break;
	case RX_FINISHED_STR_NOT_RECV: 
		return 0; 
	break;
  }
	#ifdef DEBUG_ON
		Serial.println("DB:APN OK");
	#endif
	 delay(5000);
	  
	gsm.SimpleWriteln("AT+CIICR");  

  switch(gsm.WaitResp(10000, 50, "OK")){
	case RX_TMOUT_ERR: 
		return 0; 
	break;
	case RX_FINISHED_STR_NOT_RECV: 
		return 0; 
	break;
  }
  	#ifdef DEBUG_ON
		Serial.println("DB:CONNECTION OK");
	#endif

  delay(1000);


 gsm.SimpleWriteln("AT+CIFSR");
 if(gsm.WaitResp(5000, 50, "ERROR")!=RX_FINISHED_STR_RECV){
	#ifdef DEBUG_ON
		Serial.println("DB:ASSIGNED AN IP");
	#endif
	gsm.setStatus(gsm.ATTACHED);
	return 1;
}
	#ifdef DEBUG_ON
		Serial.println("DB:NO IP AFTER CONNECTION");
	#endif
 return 0;
 }
}

int InetGSM::dettachGPRS()
{
  if (gsm.getStatus()==gsm.IDLE) return 0;
   
  //gsm._tf.setTimeout(_GSM_CONNECTION_TOUT_);

  //_cell.flush();

  //GPRS dettachment.
  gsm.SimpleWriteln("AT+CGATT=0");
  if(gsm.WaitResp(5000, 50, "OK")!=RX_FINISHED_STR_NOT_RECV)
  {
    gsm.setStatus(gsm.ERROR);
    return 0;
  }
  delay(500);
  
  // Commented in initial trial code!!
  //Stop IP stack.
  //_cell << "AT+WIPCFG=0" <<  _DEC(cr) << endl;
  //	if(!gsm._tf.find("OK")) return 0;
  //Close GPRS bearer.
  //_cell << "AT+WIPBR=0,6" <<  _DEC(cr) << endl;

  gsm.setStatus(gsm.READY);
  return 1;
}

int InetGSM::connectTCP(const char* server, int port)
{
  //gsm._tf.setTimeout(_TCP_CONNECTION_TOUT_);

  //Status = ATTACHED.
  //if (getStatus()!=ATTACHED)
    //return 0;

  //_cell.flush();
  
  //Visit the remote TCP server.
   gsm.SimpleWrite("AT+CIPSTART=\"TCP\",\"");
   gsm.SimpleWrite(server);
   gsm.SimpleWrite("\",");
   gsm.SimpleWriteln(port);
  
  switch(gsm.WaitResp(1000, 200, "OK")){
	case RX_TMOUT_ERR: 
		return 0;
	break;
	case RX_FINISHED_STR_NOT_RECV: 
		return 0; 
	break;
  }
  #ifdef DEBUG_ON
	Serial.println("DB:RECVD CMD");
  #endif	
  if (!gsm.IsStringReceived("CONNECT OK")) {
    switch(gsm.WaitResp(15000, 200, "OK")) {
	case RX_TMOUT_ERR: 
		return 0;
	break;
	case RX_FINISHED_STR_NOT_RECV: 
		return 0; 
	break;
    }
  }

  #ifdef DEBUG_ON
	Serial.println("DB:OK TCP");
  #endif

  delay(3000);
  gsm.SimpleWriteln("AT+CIPSEND");
  switch(gsm.WaitResp(5000, 200, ">")){
	case RX_TMOUT_ERR: 
		return 0;
	break;
	case RX_FINISHED_STR_NOT_RECV: 
		return 0; 
	break;
  }

  #ifdef DEBUG_ON
	Serial.println("DB:>");
  #endif
  delay(4000);
  return 1;
}

int InetGSM::disconnectTCP()
{
  //Status = TCPCONNECTEDCLIENT or TCPCONNECTEDSERVER.
  /*
  if ((getStatus()!=TCPCONNECTEDCLIENT)&&(getStatus()!=TCPCONNECTEDSERVER))
     return 0;
  */
  //gsm._tf.setTimeout(_GSM_CONNECTION_TOUT_);


  //_cell.flush();

  //Switch to AT mode.
  //_cell << "+++" << endl;
  
  //delay(200);
  
  //Close TCP client and deact.
  gsm.SimpleWriteln("AT+CIPCLOSE");

  //If remote server close connection AT+QICLOSE generate ERROR
  /*if(gsm._tf.find("OK"))
  {
    if(getStatus()==TCPCONNECTEDCLIENT)
      gsm.setStatus(ATTACHED);
    else
      gsm.setStatus(TCPSERVERWAIT);
    return 1;
  }
  gsm.setStatus(ERROR);
  
  return 0;    */
  if(gsm.getStatus()==gsm.TCPCONNECTEDCLIENT)
      	gsm.setStatus(gsm.ATTACHED);
   else
        gsm.setStatus(gsm.TCPSERVERWAIT);   
    return 1;
}

int InetGSM::connectTCPServer(int port)
{
/*
  if (getStatus()!=ATTACHED)
     return 0;
*/
  //gsm._tf.setTimeout(_GSM_CONNECTION_TOUT_);

  //_cell.flush();

  // Set port
  
  gsm.SimpleWrite("AT+CIPSERVER=1,");
  gsm.SimpleWriteln(port);
/*
  switch(gsm.WaitResp(5000, 50, "OK")){
	case RX_TMOUT_ERR: 
		return 0;
	break;
	case RX_FINISHED_STR_NOT_RECV: 
		return 0; 
	break;
  }

  switch(gsm.WaitResp(5000, 50, "SERVER")){ //Try SERVER OK
	case RX_TMOUT_ERR: 
		return 0;
	break;
	case RX_FINISHED_STR_NOT_RECV: 
		return 0; 
	break;
  }
*/
  //delay(200);  

  return 1;

}

boolean InetGSM::connectedClient()
{
  /*
  if (getStatus()!=TCPSERVERWAIT)
     return 0;
  */
  
   gsm.SimpleWriteln("AT+CIPSTATUS");
  // Alternative: AT+QISTAT, although it may be necessary to call an AT 
  // command every second,which is not wise
  /*
  switch(gsm.WaitResp(1000, 200, "OK")){
	case RX_TMOUT_ERR: 
		return 0;
	break;
	case RX_FINISHED_STR_NOT_RECV: 
		return 0; 
	break;
  }*/
  //gsm._tf.setTimeout(1);
  if(gsm.WaitResp(5000, 50, "CONNECT OK")!=RX_FINISHED_STR_RECV)
  {
    gsm.setStatus(gsm.TCPCONNECTEDSERVER);
    return true;
  }
  else
    return false;
 }

and

Code:
#ifndef _INETGSM_H_
#define _INETGSM_H_

#define BUFFERSIZE 1

#include "SIM900.h"

class InetGSM
{
  private:
    char _buffer[BUFFERSIZE];
    
  public:
    int httpGET(const char* server, int port, const char* path, char* result, int resultlength);
    int httpPOST(const char* server, int port, const char* path, const char* parameters, char* result, int resultlength);
    
    // Fast and dirty solution. Should make a "mail" object. And by the moment it does not run.
    int openmail(char* server, char* loginbase64, char* passbase64, char* from, char* to, char* subj);
    int closemail();
    int attachGPRS(char* domain, char* dom1, char* dom2);
    int dettachGPRS();
    int connectTCP(const char* server, int port);
    int disconnectTCP();
    int connectTCPServer(int port);
    boolean connectedClient();

    // This runs, yes
    //int tweet(const char* token, const char* msg);

};

#endif
 
In some/most cellular data systems, there's a "dormancy timer". After n amount of time (say, 2 minutes) of inactivity (packet flow), the data session is moved to a dormant state and the cellular base station reallocates "channel elements" (radio resources) to some other user. When your app next tries to send a packet, there is a delay while a channel element is reallocated to your session. I've seen this in Verizon and Sprint (3G) to be tens of seconds or more in the busy hour. On AT&T and T-Mobile 3G, this is longer yet. If the packet is TCP, often TCP will timeout its ACK and retransmit. Sometimes the retry counter for TCP is exhausted and the TCP connection fails. A web browser tends to hid this, since each HTTP transaction reestablishes a TCP connection as a rule.
The busy hours: morning commute, lunch, evening commute, are the worst - due to competition for radio resources. Some carriers change the dormancy timer vs. time of day.
On 2G (GPRS, which nearing end of life), it's unpredictable.
On LTE (4G), it's much better on Verizon, but I haven't tried other 4G carriers due to our need of good coverage nationally.

You can use UDP instead of TCP to avoid some of this, as long as your app has a response message in lieu of TCP's ACK. And if the local and distant sites' firewalls cooperate with UDP forwarding.

AT&T used to change the client IP address when coming out of dormancy, in 3G.

That may not be your problem, but if you keep a ping going, it can help. Vendors like Cradlepoint who do M2M on cellular have learned all the keep-alive tricks. At the root of this is economics - avoiding wasting radio channel elements which are $$$$$$.
 
Last edited:
Wow, I hadn't thought it could be a carrier issue, thanks for that input!
Another way I could get around this is by sending a batch of 11 messages, 3 seconds each, sent out every 33 seconds.
So then the batch message would be devided by commas, ie. 111,222,333,444,555... And I would later decode that using php.
What would be the best way to go about doing that? Storing them internally, then sending the batch out the same way I was sending one http post?
 
Last edited:
Status
Not open for further replies.
Back
Top