A faster 'writeModemCommand' based on timeout instead of delay

Hi,

I'm using Arduino + GSM Shield. I had to send AT commands so I was looking to the 'GSM3ShieldV1DirectModemProvider' class.
The original code is based on a delay before checking out the modem response.

I did modify the code to get faster responses.
The principle is: sending the AT command, waiting until a first response is available and then loop to the response read with timeout handling. After 100 millis with no further response bytes the loop exits.

I tested it and till now have no bad responses from this piece of code.

String GSM3ShieldV1DirectModemProvider::writeModemCommand(String ATcommand, int responseTimeout)
{	
  if(trace)
	Serial.println(ATcommand);

  // Flush other texts
  flush();
  
  //Enter debug mode.
  connect();
  
  //Send the AT command.
  println(ATcommand);

  // Waits first available data or timeout
  unsigned long start = millis();
  while((millis() - start) < responseTimeout && !available());

  //Get response data from modem.
  String result = "";
 
  while (available())
  {
    // Read response
    char c = read();
    result += c;
    
    // New byte available?
    for(int i=0; i<100; i++)
       if (!available())
          delay(1);
  }

  if(trace)
	Serial.println(result);

  //Leave the debug mode.
  disconnect();
  return result;
}

Please provide any suggestions, feedback or comments if you use this piece of code.

Thanks

this loop adds chars as fast as possible and only if there are none available it checks for the 100 msec timeout

  while (available())
  {
    while(available() ) result += read();  // read as much as possible
 
    uint8_t timeout = 100;  // uint8_t is small enough...
    while( --timeout > 0 && !available() ) delay(1);
  }

be aware that to make this code more robust you should also check for a maximum nr of characters.
In the end memory is a limited resource...

Finally using char array's instead of Strings is faster and give more control over memory used. (incl leaks)

robtillaart:
this loop adds chars as fast as possible and only if there are none available it checks for the 100 msec timeout

  while (available())

{
   while(available() ) result += read();  // read as much as possible

uint8_t timeout = 100;  // uint8_t is small enough...
   while( --timeout > 0 && !available() ) delay(1);
 }




be aware that to make this code more robust you should also check for a maximum nr of characters. 
In the end memory is a limited resource... 

Finally using char array's instead of Strings is faster and give more control over memory used. (incl leaks)

Very good enhancement ! :slight_smile:

Thanks,
Cabbi

robtillaart:
this loop adds chars as fast as possible and only if there are none available it checks for the 100 msec timeout

while (available())
{
while(available() ) result += **(char)**read(); // read as much as possible

uint8_t timeout = 100; // uint8_t is small enough...
while( --timeout > 0 && !available() ) delay(1);
}

be aware that to make this code more robust you should also check for a maximum nr of characters.
In the end memory is a limited resource...

Finally using char array's instead of Strings is faster and give more control over memory used. (incl leaks)

fix :slight_smile:

fix

guess so,

can you quantify the difference in performance and footprint (sketch size)?

minor one :wink:

int responseTimeout)
==>
unsigned int responseTimeout)

a time out cannot be negative AFAIK ...

When dealing with something as slow as a modem you might want to wait for the first character to come through before you execute this script? If you don't it might fail on the first 'while(available())'.

dannable:
When dealing with something as slow as a modem you might want to wait for the first character to come through before you execute this script? If you don't it might fail on the first 'while(available())'.

...and that's exactly what it does (you're looking only at a piece of the entire code), which is:

String GSM3ShieldV1DirectModemProvider::writeModemCommand(String ATcommand, unsigned int responseTimeout)
{ 
  if(trace)
 Serial.println(ATcommand);

  // Flush other texts
  flush();
  
  //Enter debug mode.
  connect();
  
  //Send the AT command.
  println(ATcommand);

  // Waits first available data or timeout
  unsigned long start = millis();
  while((millis() - start) < responseTimeout && !available());

  //Get response data from modem.
  String result = "";

  while (available())
  {
    while(available() ) result += (char)read();  // read as much as possible
 
    uint8_t timeout = 100;  // uint8_t is small enough...
    while( --timeout > 0 && !available() ) delay(1);
  }

  if(trace)
 Serial.println(result);

  //Leave the debug mode.
  disconnect();
  return result;
}

BTW... I've read lots of posts talking about timeout rollover after 49.2 days. Please notice that due the fact (millis()-start) are both unsigned, the math still works even if millis() rolls over.

Just print this out:

unsigned long past = 4294967285;  // 10 millis before the roll over
unsigned long now = 10;           // Now after the roll over
Serial.println((unsigned long)now-past);