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.
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)
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);