Using arduino-timer lambda function inside a class

I'm working with class and I need a timer, I decided to use an object from arduino-timer library (GitHub - contrem/arduino-timer: Non-blocking library for delaying function calls).
I have some problem declaring the callback function because it wants a static function but I have to call it from a method of the class.

I discovered that lambda declaration can help me, I can declare the function on the fly. This is the example of the library:

timer.in(1000, [](void *argument) -> bool { return argument; }, argument);

It can work for me, but I need a reference to "this" to run a method of the class inside the function.
How can I pass "this" as argument to the lambda function?

class Test {

    Timer<1>  timer;
    void doIt();
    void runTimer() {
      timer.in(1000, [](void* that) -> bool {
        that->doIt() //I need this->doIt() inside this lambda function
      }, this);
    }


}

This is an example of how I use it. The variables have to be declared globally

timer.setTimeout(5000L, []()
    {
      ReCnctFlag = 0;
      ReCnctCount++;
      Blynk.connect();
    });

I've beaten my head against the wall several times trying to do something like that. Could never make it work. Don't think your idea will either. Pointers to instance functions are Odd Ducks (read about them here). Trying to use Lambdas with them makes it even more complex. If you google around, you'll find lots of mumbo jumbo about how the closure captures the variables.

Fortunately, you're going about it the wrong way.

The library's author provided for a case like this. Try something like:

#include <arduino-timer.h>

class Test {
  public:
    Timer<1>  timer;
    bool doIt() {
      Serial.println("In Callback");
      return true;
    }
    void initTimer() {
      timer.every(1000, callback, this);
    }
    void tick() {
      timer.tick();
    }

    static bool callback(void *p) {
      Test *ptr = (Test *)p;
      return ptr->doIt();
    }
};

Test test;

void setup() {
  Serial.begin(115200);
  delay(1000);
  test.initTimer();
}

void loop() {
  test.tick();
}
1 Like

Are you just looking for something to happen when a timer expires?

-jim lee

jimLee:
Are you just looking for something to happen when a timer expires?

-jim lee

Yes, but I need to use a class methods inside the timer function callback.
I would like to have "this" argument in the callback function so I use all the public methods of the class.

In a really short abstract:
I have a "door" class to handle a door entity, lock and handle the semaphone on it. Each door instance has the opposite door linked, so a door can lock or switch the semaphore of the opposite door.

I have a lock() and unlock() methods with many operations (lock this, lock the opposite door and change their semaphores accordling). When I unlock a door I want to run a timer to lock it again, this is why I want a timer inside a class method and why I want to re-use a class method in the timer callback.
Many thank for your help

Proietti:
This is an example of how I use it. The variables have to be declared globally

timer.setTimeout(5000L, []()

{
     ReCnctFlag = 0;
     ReCnctCount++;
     Blynk.connect();
   });

Thanks Proietti,
but I need the timer inside a class, this is exactly the point: I cannot use a static function.

gfvalvo:
I've beaten my head against the wall several times trying to do something like that. Could never make it work. Don't think your idea will either. Pointers to instance functions are Odd Ducks (read about them here). Trying to use Lambdas with them makes it even more complex. If you google around, you'll find lots of mumbo jumbo about how the closure captures the variables.

Fortunately, you're going about it the wrong way.

The library's author provided for a case like this. Try something like:

#include <arduino-timer.h>

class Test {
 public:
   Timer<1>  timer;
   bool doIt() {
     Serial.println("In Callback");
     return true;
   }
   void initTimer() {
     timer.every(1000, callback, this);
   }
   void tick() {
     timer.tick();
   }

static bool callback(void *p) {
     Test *ptr = (Test *)p;
     return ptr->doIt();
   }
};

Test test;

void setup() {
 Serial.begin(115200);
 delay(1000);
 test.initTimer();
}

void loop() {
 test.tick();
}

Many many thanks gfvalvo!
I tought it would be possible and simplier to capture "this" inside a lamba. I cannot say this is a straight solution but it works! ;D

Umm.. ok. Let me know if you'd like to see another approach.

-jim lee

Of course, please let me know.

Quick question..

"When I unlock a door I want to run a timer to lock it again."

Is this if you unlock yourself? (as a door) Or the door you are linked to? Or both?

If both, would it true that any time you (as a door) is unlocked, no matter by whom, you only stay unlocked for a fixed amount of time? Kinda' like "Auto relock".

-jim lee

It is a bit more complicated... usually I try to keep the problem simple when posting in a forum. This time I'm going to waste a bit of your time explaning the project.

This is a project for an hospital, they will use a Controllino as plc to manage a 4-way crossing inside the building.
There will be 4 doors, 2 allowed paths, when you enter from one door you can exit only to the opposite one and you cannot turn left or right. The door works like an elevator, there is a call button to enter if all other doors are closed, and there is a red/green semaphore and an electromagnet to lock/unlock the door.


There are some more signals, but the main logic is this:

  • when you call the btn, if all doors are closed and blocked, the door near the buttun will be unlocked, the semaphore turns green

  • when the door is unlocked there is a timer, if the door will be not opened before the timeout, this will be blocked again.

  • when the door is opened the timer stops and the lock is reinforced

  • when the door is closed the path is free again for other entrance BUT mind the next point!

  • one of the two paths is a "covid" path (door 3/4), this means that after the door closing the passage is blocked for a fixed amount of time to let the automatic disinfection. After the timer, the passage is free again for the next call.

This is more or less the project, as you can imagine, is not so straight. For example, the doors are not all the same. There is a manual door with electromagnet, but there is also an automatic door with signal to open and close and so on. This is why I wanted to use classes, now I have Door superclass, ManualDoor class, SlidingDoor class and so on.

Coming back to the question, inside my class I have to handle some timers (covid disinfection timer, door opening timeout, led blinking ...), for example the door opening timeout has to block the door again at the timeout. This is why I need to use a class method in the timer callback.

This is the example using gfvalvo solution:

class Door {

    Timer<1>  closeTimer;
    
    void lock();

    void eventCallBtn(){
        closeTimer.cancel();
        closeTimer.in(CALL_TIMEOUT, callback, this);
        }
    }
    
    static bool callback(void *p) {
      Door *ptr = (Door *)p;
      return ptr->lock();
    }
    
    void lock(){
        digitalWrite(LEDRED_PIN,HIGH);
    }
}

class ManualDoor : public Door {
    
    void lock(){
        Door::lock();
        digitalWrite(ELECTROMAGNET_PIN,HIGH);
    }
}

class SlidingDoor : public Door {
    
    void lock(){
        Door::lock();
        digitalWrite(CLOSEDOORSIGNAL_PIN,HIGH);
    }
}

Oh!

So there are two stages to a door opening... First is unlock(I'm ok to open) Second is open. It will only open if the one across the way says its ok. Correct?

There is a lock timeout and there is a disinfect time out if a covid door opens.

Let me think about this for a bit. Looks like a fun project.

-jim lee

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.