Timer library and callbacks to class functions

Hi all,

Relatively new to the Arduino but already own 3, really enjoying the making and experimenting. Currently working on a rover project and looking to streamline my code using a scheduler and libraries.

I am using the standard Timer library by Simon Monk:

http://playground.arduino.cc/Code/Timer

I have the following code, essentially wanting to schedule repeated calling of function update_gps in library Rover_GPS, however I get the compilation error on the line within Setup - "error: no matching function for call to 'Timer::every(int, , int)'".

I suspect this is something to do with pointers and the fact the function is in a class (I can schedule a function defined directly in the sketch fine).

Most grateful for some assistance in getting this going.

#include <Rover_GPS.h>

#include <Event.h>
#include <Timer.h>

Rover_GPS rover_gps;

Timer scheduler;


void setup() {

  scheduler.every(100, rover_gps.update_gps, 0);
  
}

void loop() {
 scheduler.update();
}

Suppose you create multiple instances of your class. Which instance should the method be called for, when the timer event happens?

The compiler doesn't know, and there is no way for you to tell it. If you are going to use a method, it must be a static methods. Static methods are shared by all instances of the class, so the compiler is relieved of the responsibility of determining which instance to call the method on.

Of course, you are then responsible for determining that.

Hi Paul,

Thanks for your response, I may misunderstand but I thought by specifying rover_gps.update_gps (rather than say a second instance declared as rover2_gps and a call to the timer with rover2_gps.update_gps) that I was referencing the initial instance of Rover_GPS created?

Version 2.0 of the Timer library introduced a context argument that is passed back to the callback functions. Does the update_gps method accept a void pointer? I can't tell since I don't have the Rover_GPS library. Can you provide a link?

Welcome to the forum. In the future, please use code tags.

Hi Jack,

Original post modified with code tag, thanks.

The Rover_GPS library is my own, I'm just building the skeleton structure of a library based sketch trying to make ongoing development and maintenance more efficient.

Yes I noticed the context argument (but honestly not quite clear on it), I currently have the following in the .h file

class Rover_GPS
{
  public:
    Rover_GPS();        //Constructor
    void update_gps(void* context);
    
};

and the following in the .cpp file:

void Rover_GPS::update_gps(void* context)
{
}

I have temporarily resolved the issue by creating local "wrapper" functions which are handed to the scheduler which in turn call the class instance function as determined by the global variable, so:

#include <Rover_GPS.h>
...
Rover_GPS rover_gps;
Timer scheduler;
...
...
void setup() {
  scheduler.every(100, update_gps, 0);
}

void update_gps(void* context) {
  rover_gps.update_gps();
}

Of course I would have liked to callback the class function directly to save a few lines but this works.

What Paul is saying is that the code for a method is normally shared among all instances of a class unless it is declared static. Declaring a method static allows it to be referenced for each given instance of the class, as it duplicates the code. Of course this adds to overall code size but it depends on how many instances, etc. I suspect this may be a singleton class so maybe not an issue.

(Correct me if I didn't get that right, Paul.)

So I ended up with the following. I had to code an empty constructor for the class, I didn't think that was required, but I probably need to review.

Main sketch

#include "Rover_GPS.h"
#include <Timer.h>

Rover_GPS rover_gps;
Timer scheduler;

void setup(void)
{
    scheduler.every(100, rover_gps.update_gps, 0);
}

void loop(void)
{
    scheduler.update();
}

Rover_GPS.h

class Rover_GPS
{
    public:
        Rover_GPS();        //Constructor
        static void update_gps(void* context);
};

Rover_GPS.cpp

#include "Rover_GPS.h"

Rover_GPS::Rover_GPS()
{
}

void Rover_GPS::update_gps(void* context)
{
}

Grumpybeard:
Yes I noticed the context argument (but honestly not quite clear on it), I currently have the following in the .h file

It allows a single callback function to be used for multiple events, but still gives that function a way to determine which event fired.

Hi Jack,

Just tried your adjustment using the "Static" keyword and it compiles just fine, cheers, much appreciate you coming back to me swiftly on this, looks like I have a long night ahead but I can progress :smiley:

I'll take a look at the contents of the context argument.

Thanks again.