Sometimes you may need to wait for a certain condition to become true, but you don't want to wait forever: it may be awaiting for Serial, for the Wifi to connect to a network, or the response from a SoftwareSerial peripheral. The await
construct lets you put an upper bound to the time you're willing to wait.
Most often, you see example code of this kind:
Serial.print("Attempting to connect to WiFi");
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(500);
}
If the connection doesn't succeed (maybe the AP is out of range or is down), you're stuck in an endless wait. A proper way for handling such situations is with a timeout that gets you out of the loop with an error status so you can handle the failure.
await
is exactly this: a construct to await for a condition to become true until a timeout expires, returning true or false as a response.
Definition
#define await(condition, timeout) await_with_interval(condition, timeout, 10)
#define await_with_interval(condition, timeout, interval) \
([]() { \
uint32_t start = millis(); \
while (millis() - start <= timeout) { \
if (condition) return true; \
delay(interval); \
} \
return false; })()
How to use
await
needs at least two arguments:
- the condition to await for
- the timeout, in milliseconds
// these are for greater code readability
#define Millis
#define Second *1000
#define Seconds *1000
bool wifiConnected = await(WiFi.status() == WL_CONNECTED, 10 Seconds)
The code above will wait 10 seconds for the wifi to connect: on failure, wifiConnected
will be false and you can gently fail.
You can use it for any kind of check, like waiting for Serial
.
bool serialReady = await(Serial, 5 Seconds)
bool serialHasCharacters = await(Serial.available(), 5 Seconds)
The default interval between checks is 10 milliseconds: if you need a custom delay interval you can use the more verbose await_with_interval
:
// await WiFi for 10 seconds, check if connected every 500 millis
bool wifiConnected = await_with_interval(WiFi.status() == WL_CONNECTED, 10 Seconds, 500 Millis)
How it works
The await
macro creates an inline function that loops until the timeout expires. At every loop it checks if the condition is true: if that's the case, it returns true. The inline function construct is needed to get a return value, so you can assign it to a variable or embed directly inside an if
test. The following code sample gives you an idea of what's happening.
bool wifiConnected = await(WiFi.status() == WL_CONNECTED, 10 Seconds)
// conceptually translates to
bool inline_function() {
uint32_t start = millis();
while (millis() - start <= 10000) {
if (WiFi.status() == WL_CONNECTED)
return true;
delay(10);
}
return false;
}
bool wifiConnected = inline_function();