Wait and timeout in Particle.function()

I am trying to set some parameters on the hardware, wait for a response and return the result through a Particle.function()

One way I thought of implementing is the use of:

void setParam(String value) {
    call_this_function(value);

    last_updated_time = millis();
    while (millis() - last_updated_time < 3000) {
        if (new_result != old_result) {
            return 0;
        }
    }

    return 1;
}

This there a smarter way to do something like this using Particle.function()?

That will work with a few caveats:

  • At 3 seconds, you’re probably OK but there is point where the cloud side will believe that the device has not responded and will return an error.
  • During the time you block the function handler, the loop() thread will not run, because function handlers are dispatched between calls to loop.
  • You probably will want a delay(1) or os_thread_yield in your while loop so other threads will more CPU time while waiting.
1 Like

Is there a better way besides doing delay(1)?

@kennethlimcp, the delay(1) falls in line with the millis() test which won’t change for 1ms anyway. And don’t forget that, at best, the loop() thread runs every millisecond. As @rickkas7, points out, both delay(1) and os_thread_yeild() will allow other threads to run as the while() runs. Either way, loop() generally gets back control every ms or so.

The challenge is with your synchronous call of Particle.function() where you call a function and expect to return a (delayed) value as a result.

Another approach might be to decouple the status from the Particle.function() by having a Particle.variable() to represent the status. You could even decouple further and set a flag in the Particle.function() that loop() picks up and runs a small FSM to do the call_this_function(value), wait for the prescribed period and set the Particle.variable() status variable accordingly. You get the idea.

1 Like

Yes definitely understand what you guys are talking about. :smiley:

Just wondering if there’s a more elegant way to do it without having to retrieve the value via Particle.variable()

@kennethlimcp, not really since Particle.function() calls are serviced in the user thread. Depending on the calling server/service, you could have the FSM in loop() fire off a Particle.publish() to indicate the status so you don’t need to call the variable.

1 Like

I did some testing and it seems like even with a delay(10), main loop() doesn’t seem to execute during that period.

Added a print statement to the Particle.function() and it simply executes in the while() loop and the variable that gets updates in loop() is always displaying false (even though on the hardware it has changed the lights when it became true)

Correct. The loop function will never execute while in a Particle.function handler or a code-based variable handler, because they are dispatched between calls to loop() from the application thread.

When in non-threaded mode, Particle.process() will keep the cloud connection alive, but in threaded mode it doesn’t do anything in this case. And in no case does loop() ever get called from inside Particle.process() or delay(), as that would often cause loop() to be reentrant, which would cause all sorts of trouble.

I would break up your setParam() .

Do the asynch value checking in its own function that returns a negative response code called something like WOULD_BLOCK when your timer has not expired and the value has not been set as you expect.

After the timer has expired (or the value has been set correctly) only then return true or false according to your logic.

This routine would be called in loop().

setParam() “starts” the timer from a logical sense.

The thing here is that you are not blocking.