Problem with setTimeout

Hi guys,

When ever I use setTimeout it ends up waiting that amount of time before retreiving any data, when I am not using it, the data gets received much faster but I still need it as my bluetooth module needs some time, I don’t want to use delay’s and go all hacky on the thing. Here is my code am I doing something wrong?

/*
  Example Bluetooth Serial Passthrough Sketch
 by: Jim Lindblom
 SparkFun Electronics
 date: February 26, 2013
 license: Public domain

 This example sketch converts an RN-42 bluetooth module to
 communicate at 9600 bps (from 115200), and passes any serial
 data between Serial Monitor and bluetooth module.
 */
#include <SoftwareSerial.h>  

int bluetoothTx = 2;  // TX-O pin of bluetooth mate, Arduino D2
int bluetoothRx = 3;  // RX-I pin of bluetooth mate, Arduino D3

SoftwareSerial bluetooth(bluetoothTx, bluetoothRx);

void setup()
{
  Serial.begin(9600);  // Begin the serial monitor at 9600bps

  bluetooth.begin(115200);  // The Bluetooth Mate defaults to 115200bps
  bluetooth.print("$$");
  delay(100);  // Short delay, wait for the Mate to send back CMD
  bluetooth.println("U,9600,N");  // Temporarily Change the baudrate to 9600, no parity
  // 115200 can be too fast at times for NewSoftSerial to relay the data reliably
  bluetooth.begin(9600);  // Start bluetooth serial at 9600
  bluetooth.setTimeout(10000);
  bluetooth.print("$$");
  Serial.println("Started");
  String return_val = bluetooth.readString();
  if (!return_val.startsWith("CMD"))
  {
    Serial.println("Failed to enter command mode");
    return;
  }

  Serial.println("Entered command mode, querying devices");
  bluetooth.println("I");
  return_val = bluetooth.readString();
  if (!return_val.startsWith("Inquiry"))
  {
    Serial.println("Failed to start inquiry");
    return;
  }

  
  Serial.println("Inquiry started waiting for device count");
  return_val = bluetooth.readString();
  if (!return_val.startsWith("Found"))
  {
    Serial.println("No devices in range");
    Serial.println(return_val);
    return;
  }

  int total_found = return_val.substring(6).toInt();
  Serial.print("Found: ");
  Serial.print(total_found);
  Serial.println(" devices");

  for (int i = 0; i < total_found; i++)
  {
    return_val = bluetooth.readString();
    Serial.println(return_val);    
  }
}

void loop()
{
  if(bluetooth.available())  // If the bluetooth sent any characters
  {
    // Send any characters the bluetooth prints to the serial monitor
    Serial.print((char)bluetooth.read());  
  }
  if(Serial.available())  // If stuff was typed in the serial monitor
  {
    // Send any characters the Serial monitor prints to the bluetooth
    bluetooth.print((char)Serial.read());
  }
  // and loop forever and ever!
}

danielmccarthy:
but I still need it as my bluetooth module needs some time,

The default is 1 second. This isn't enough time?

No it takes 7-8 seconds to receive the scan from the bluetooth device

Any help please? Is the setTimeout supposed to wait because that is what seems to be happening. My board is Arduino UNO.

What goes wrong when you don't set the timeout to ten seconds?

Ok, 1 second is not enough for it to read data from the bluetooth it will time out before it has a chance to read it, When I set it to 10 seconds instead of timing out after 10 seconds it just does not read the data until 10 seconds.

Can somebody check my code and see if I have made a mistake?

Thanks

What are you communicating with?

I've done several projects with Bluetooth but not with an Arduino.

The strategy used to receive data is very different than those with which I'm familiar.

It might help if you let us know what the data being sent looks like.

Ok then so when I said 'I' after entering command mode by sending "$$$" it will search for bluetooth devices the output is:

Inquiry,T=7,COD=0
Found 1
94EBCD010FE8,BLACKBERRY-BE09,7A020C
Inquiry Done

Now this takes a while to search up to 8 seconds like I said. Now I have appended my code to delay 8 seconds just before calling readString() what happens then is it works fine. But this is a very hacky approach and is ridiculas. This is what the setTimeout function is supposed to be used for and when I do use it readString will wait until the 8-10 seconds are up before attempting to read? Why is this? I have looked in the arduino core files and the code looks fine to me so their must be something going wrong in my program causing setTimeout not to work properly.

danielmccarthy:
BUMP

Don't do that. It's really frowned upon around here.

danielmccarthy:
BUMP

Don't do that.

If it's been more than a day, you could add some additional information or tell us other things you tried but don't just bump a post because you've had to wait 34 minutes. (Edit: Apparently the first bump was deleted.)

I just noticed, this is just part of the setup process. IMO, it's not a big deal to use delay as part of setting up a device.

I'm working on some JPEG camera interface and the camera needs a few seconds after it has been reset before other commands are issued. I don't have a problem adding a delay after resetting the camera because there isn't anything else the program can be doing. It seems the same is true for your program. You need to wait for the BT device to search for other BT devices.

You can either use a longer timeout or you can use delay. I don't think either looks ridiculous.

Your question about how setTimeout works is a valid question. I don't know the answer. The person who does know the answer may be asleep on the other side of the world. Give people time to see the question.

Is it really waiting that long to read or is it waiting that long to return the String to you? The timeout is how long it must go without getting a character before it returns the String it read. The only other way it exits that function is if it gets a 0, null character. If there is no null terminator on the string that whatever device you are reading is sending, then it will read and add to the string until the device stops sending more characters and then wait for the length of the timeout period before realizing it isn't going to get another character and returning.

So if you know how long it takes said device to gather the information and start transmitting, it would be better to delay for that long and not mess with the timeout. Or if the device is something you can control, then make sure you are sending a 0 (not '0') at the end of the transmission to let readString know the transmission is complete.

I already tried all of this, I have no control of the bluetooth device’s serial data, it is built into its own firmware of the device its self. I have modified my code and this works fine but I think the delay is sloppy. I still don’t understand why the setTimeout is causing the program to wait for that length of time rather than try to receive data for that length of time. Here is the new source:

/*
Example Bluetooth Serial Passthrough Sketch
by: Jim Lindblom
SparkFun Electronics
date: February 26, 2013
license: Public domain

This example sketch converts an RN-42 bluetooth module to
communicate at 9600 bps (from 115200), and passes any serial
data between Serial Monitor and bluetooth module.
*/
#include <SoftwareSerial.h>

int bluetoothTx = 2; // TX-O pin of bluetooth mate, Arduino D2
int bluetoothRx = 3; // RX-I pin of bluetooth mate, Arduino D3

SoftwareSerial bluetooth(bluetoothTx, bluetoothRx);

struct BLUETOOTH_DEVICE
{
String bt_id;
String bt_name;
};

void setup()
{
Serial.begin(9600); // Begin the serial monitor at 9600bps

bluetooth.begin(115200); // The Bluetooth Mate defaults to 115200bps
bluetooth.print("$$$");
delay(100); // Short delay, wait for the Mate to send back CMD
bluetooth.println(“U,9600,N”); // Temporarily Change the baudrate to 9600, no parity
// 115200 can be too fast at times for NewSoftSerial to relay the data reliably
bluetooth.begin(9600); // Start bluetooth serial at 9600
bluetooth.print("$$$");
Serial.println(“Started”);
String return_val = bluetooth.readString();
if (!return_val.startsWith(“CMD”))
{
Serial.println(“Failed to enter command mode”);
return;
}

Serial.println(“Entered command mode, querying devices”);
bluetooth.println(“I”);
return_val = bluetooth.readString();
if (!return_val.startsWith(“Inquiry”))
{
Serial.println(“Failed to start inquiry”);
return;
}

Serial.println(“Inquiry started waiting for device count”);
delay(8000);
return_val = bluetooth.readString();
if (!return_val.startsWith(“Found”))
{
Serial.println(“No devices in range”);
Serial.println(return_val);
return;
}

int total_found = return_val.substring(6).toInt();
Serial.print(“Found: “);
Serial.print(total_found);
Serial.println(” devices”);

BLUETOOTH_DEVICE* devices = new BLUETOOTH_DEVICE[total_found];

for (int i = 0; i < total_found; i++)
{
delay(1000);
String bt_id = bluetooth.readStringUntil(’,’);
String bt_name = bluetooth.readStringUntil(’,’);
// We don’t care about the final argument but we still need to read it so its out of the buffer
bluetooth.readString();
devices*.bt_id = bt_id;*
devices*.bt_name = bt_name;
_
}_
for (int i = 0; i < total_found; i++)
_
{_
_
Serial.print("Bluetooth ID: ");_
Serial.print(devices.bt_id);
_ Serial.println();
Serial.print("Bluetooth Name: ");_
Serial.print(devices.bt_name);
_ Serial.println();
}
// We are done*

* delete devices;
}
void loop()
{
if(bluetooth.available()) // If the bluetooth sent any characters*

* {
// Send any characters the bluetooth prints to the serial monitor*

* Serial.print((char)bluetooth.read());
}
if(Serial.available()) // If stuff was typed in the serial monitor*

* {
// Send any characters the Serial monitor prints to the bluetooth*

* bluetooth.print((char)Serial.read());
}
// and loop forever and ever!
}*_

danielmccarthy:
I still don't understand why the setTimeout is causing the program to wait for that length of time rather than try to receive data for that length of time.

I just explained that to you:

Delta_G:
If there is no null terminator on the string that whatever device you are reading is sending, then it will read and add to the string until the device stops sending more characters and then wait for the length of the timeout period before realizing it isn't going to get another character and returning.

That's how the timeout stuff works. Go look in the core at the Stream class to convince yourself.

The delay in this case isn't sloppy. This is exactly why there is a delay function, for those times when you honestly have nothing else to do and must wait for a while. It's not always evil, just when you want something else to happen during that time. In this case you don't so delay away.

Here:

From Stream.cpp:

String Stream::readString()
{
  String ret;
  int c = timedRead();
  while (c >= 0)
  {
    ret += (char)c;
    c = timedRead();
  }
  return ret;
}

So for each character it calls timedRead. And if it doesn’t receive a 0 it calls timedRead again.

also from Stream.cpp

// private method to read stream with timeout
int Stream::timedRead()
{
  int c;
  _startMillis = millis();
  do {
    c = read();
    if (c >= 0) return c;
  } while(millis() - _startMillis < _timeout);
  return -1;     // -1 indicates timeout
}

So the timeout is per character, not per transmission. You can set it long enough that the first character doesn’t time out, but then the last one has to and will take that long. Or you can set it so that the last character doesn’t take so long to time out but then you have to delay long enough for your transmission to start.

Please follow this link and read the directions.

I'm aware its per character, sorry I don't think I am explaning myself correctly let me try again

When I set the time out I am expecting it to try and get data and keep trying until the time out is reached. I understand this is on a per byte basis.

What is instead happening is it will wait until the time out has been reached, then attempt to get data.

I am not kidding this appears to be happening, the higher I set the time out the longer it takes to read data.

Right now I just set the timeout to 60000 and it is going to wait 60 seconds before receiving any data lol.

Do you know the location of the millis() function

Is it waiting before it attempts to get the data or is it waiting before it returns the data. How would you be able to tell the difference?

I tell you, it's not waiting before it makes an attempt. It is pulling in data as soon as it comes out and waiting for the last null character that never arrives.

Yes, it takes longer to get your String returned. The readString method takes that long to finish, but not because it isn't starting to read data just as soon as you call it. It's because it is waiting at the end, it has all the data, but it isn't getting back to you because it is waiting at the end for 10 seconds until it is sure that another character isn't coming. So if you have timeout set to 10 seconds and it takes 7 seconds for the first character to arrive, you're waiting 17 total seconds. 7 seconds for the transmission to start, then it reads in the data real fast, and then it waits an additional 10 seconds before returning.

I see my bad, I don't believe the bluetooth device sends the NULL terminator, it sends a new line and carraige return. This would explain why it is waiting for the length of the timeout provided. Anyway around this mate?

Maybe readStringUntil()?

danielmccarthy:
I see my bad, I don't believe the bluetooth device sends the NULL terminator, it sends a new line and carraige return. This would explain why it is waiting for the length of the timeout provided. Anyway around this mate?

Yes, leave the timeout at 1 second default value and use a delay to wait for your bluetooth device to do its thing.

Or use the available() method to wait in an empty while loop until it starts sending. But either way, you're still doing nothing for 7 or 8 seconds while you wait for the bluetooth to do its thing.

while(bluetooth.available() == 0){}
String return_val = bluetooth.readString();