How to use Timer inside a C++ class

Hey Guys/Gals,

I’m loving the ease of use when developing code for the Photon, but I’m seeing a little lack in the documentation. No biggie for something that’s growing this fast, but as such I need a little help with the Timer class.

I’d like to add a Timer to my Door class, but I can’t get the timer to call another function in the class.

Door::Door(int pin) {
    _timer = new Timer(OPEN_DOOR_TIME, &Door::alarm);
}

This is based on the interrupts which would use the following code (from the reference)…

Robot() {
    attachInterrupt(D2, &Robot::handler, this, CHANGE);
}

Unfortunately, I get

Door.cpp:17:52: error: no matching function for call to 'Timer::Timer(unsigned int, void (Door::*)())'
     _timer = new Timer(OPEN_DOOR_TIME, &Door::alarm);
                                                    ^
Door.cpp:17:52: note: candidates are:
In file included from ./inc/application.h:52:0,
                 from Door.h:5,
                 from Door.cpp:2:
../wiring/inc/spark_wiring_timer.h:34:5: note: Timer::Timer(unsigned int, Timer::timer_callback_fn)
     Timer(unsigned period, timer_callback_fn callback_) : handle(nullptr), callback(callback_) {
     ^
../wiring/inc/spark_wiring_timer.h:34:5: note:   no known conversion for argument 2 from 'void (Door::*)()' to 'Timer::timer_callback_fn {aka void (*)(Timer&)}'
../wiring/inc/spark_wiring_timer.h:32:5: note: Timer::Timer(unsigned int, void (*)())
     Timer(unsigned period, void (*callback)()) : Timer(period, timer_callback_fn(callback)) {}
     ^
../wiring/inc/spark_wiring_timer.h:32:5: note:   no known conversion for argument 2 from 'void (Door::*)()' to 'void (*)()'

Try the tip in this thread

1 Like

Hi all-

Not having much luck figuring out the correct expression in order to use Timer in one of my classes. Can anyone help?

#include "AnyClass.h"
#include "application.h"

AnyClass::AnyClass() {}

void AnyClass::method() {
  Timer timer(1000,[this]()-> void {callback;} );
  timer.start();
}

void AnyClass::callback() {

}

Class methods are supported on timers from 0.4.9. Before then, the callback has to be a plain function (or a static class method.)

I think I could work with a static method. What would the lambda expression for callback look like?

You don’t need a lambda expression (which isn’t supported pre 0.4.9) simply pass in the name of the static function, e.g

Timer(1000, AnyClass::timerCallaback)
1 Like

After going down the rabbit hole and reading everything on the subject of non-static member functions I could find, the solution turns out to be quite simple.

This allows me to initiate Timer from inside an instance and callback a method inside of my class:

Timer(1500,reinterpret_cast<void (*)()>(&MyClass::classMethod));

Not sure of any downsides, but will continue to test.

@steelydev, did you see the documentation for the latest 0.4.9 release:

https://docs.particle.io/reference/firmware/photon/#software-timers

Look under “class member callbacks” :wink:

The downside is that the this pointer will be invalid in the member function since the caller isn’t pushing that to the stack. So then you might as well make it a static member function to ensure the this pointer isn’t used, then the cast isn’t necessary.

1 Like

Thanks @peekay123, I didn’t realize there was a new system firmware release.

I’m trying to use Timer from INSIDE one of my non-static member functions so I don’t have to block for pin timing delays. I also need to delay for a substantial amount of time in order to allow the device I’m controlling to go through it’s cycle.

I’m trying:

Timer(delay,&Device::pinsLow,this,true);

but it will not compile.

Another question I have is:

When I’m using Particle Dev, how does it know what system firmware version to target? Does it read the Photon I’m targeting?

Ping @mdma

@mdma You are correct! I tested my program for DAYS and all the debug statements seemed to indicate that I was actually manipulating an instance of my class. And I was getting good behavior. But once you raised the gotcha I re-scrutinized my logs and sure enough, there were a couple of times an increment did not occur on my instance. And one where an increment showed as a decrement. So I’ve been running along happily poking random memory without a crash. Wow. Thanks for straitening me out. Now I just have to figure out how to use the new Timer…

The third parameter is a reference to the instance, not a pointer, so you need to dereference *this:smile:

Timer(delay,&Device::pinsLow,*this,true);
3 Likes

Here’s a solution I just worked up and tested. Seems to work. Created a “leds” class that blinks leds connected to gpio pins and some methods to control them, based on Timers:

Leds.h:

#include "application.h"
class Leds
{
      private:
        int led_state;
        int r;
        int p;
        Timer *tp;
        void blink (void);
      public:
          Leds (int pin, int rate, int state);
        void changePeriod (int t);
        void start (void);
        void stop (int s);
};

Leds.cpp:

#include "leds.h"
#include "application.h"

void
Leds::blink ()
{
        char ststr[40];
        led_state = !led_state;
        sprintf (ststr, "New state: %d", led_state);
        digitalWrite (p, led_state);
}

void
Leds::changePeriod (int t)
{
        tp->changePeriod (t);
}

void
Leds::start ()
{
        tp->start ();
}

void
Leds::stop (int s)
{
        tp->stop ();
        digitalWrite (p, s);
        led_state = s;
}
Leds::Leds (int pin, int rate, int state)
{
        led_state = state;
        p = pin;
        pinMode (pin, OUTPUT);
        digitalWrite (p, led_state);
        r = rate;
        tp = new Timer (rate, &Leds::blink, *this);
}

main.ino:

#include "leds.h"
Leds l1 (D0, 10000, 0);
Leds l2 (D1, 5000, 0);

void
setup ()
{
        l1.start ();
        l2.start ();
}

static int nloops = 0;
void
loop ()
{
        while (nloops++ < 4)
          {
                  Particle.publish ("Loop", "v3.1");
                  delay (10000);
                  l1.changePeriod (2000);
                  l2.changePeriod (3000);
                  delay (10000);
                  l1.changePeriod (500);
                  l2.changePeriod (1500);
                  l1.stop (1);
          }
}
2 Likes

Just a note on my last example, in case you wondered, there is some “noise” code left over from testing, like in leds.cpp the sprintf() I used when I published events to see if the blink() method was called. Needs cleaning up…

Hi,
I'm now trying your code above.
Can you assist me with the code above?
Because I don't understand the part

and also this part.

Right me if I'm wrong,
At first, you set the 'rate' of the LEDs and then in the loop you change the period.
Is it the same?

What does this do? Leds l1 (D0, 10000, 0);
and this? l1.changePeriod (2000);

I'm confused...
Please assist me.
Thank you.

and…
One more question…
What is the while loop for?

:sweat_smile:

There is the implementation of Class Leds to look at. That should make things clear.
Looking at that everything becomes clear in not time.

Standard C++ syntax:
Leds l1(...) calls the constructor Leds::Leds(...).
l1.changePeriod(...) calls the class method Leds::changePeriode(...).

The while() look is just there to illustrate that the LED blinking even happens when the flow is “trapped”.

I have read the library, but I’m just confused when testing it in the real world…
the LED seems to continuously run although I put it in the setup (where it should be run one time).
There is where I’m confused…:sweat_smile:

The whole reason for that blink class is to have the LEDs running independent of your code.
After all the thread topic does explicitly deal with independent Timers.

If you don’t just copy the code but read the discussion in this tread, you see the reason behind the code.