0

Using the RPI Pico SDK, I have three files. I want to use a callback function and access private members of a class. The callback function is in an SDK and I can not modify it. How do I do this?

/////// test.h
bool main_loop_timer_callback(struct repeating_timer *t);
class MyClass {
private:
    static int count;
    struct repeating_timer main_loop_timer;
public:
    MyClass();
    friend bool main_loop_timer_callback(struct repeating_timer *t);
};

//////// test.cc
#include <iostream>
#include "pico/stdlib.h"
#include "test.h"
using namespace std;
bool main_loop_timer_callback(struct repeating_timer *t) {
    MyClass::count++;
    cout << "callback " << MyClass::count << endl;
    return true;
}

MyClass::MyClass() {
    add_repeating_timer_us(-50000,
                           main_loop_timer_callback,
                           NULL,
                           &main_loop_timer);
    count = 0;
};

/////// test-main.cc
#include "pico/stdlib.h"
#include "test.h"
using namespace std;
int main() {
    MyClass test;
    stdio_init_all();
}
Hasturkun
  • 35,395
  • 6
  • 71
  • 104
  • please show how you are compiling plus the complete error message – pm100 Feb 05 '23 at 21:34
  • Learn about [*lambdas*](https://en.cppreference.com/w/cpp/language/lambda) which can *capture* variables, including `this`. So you could have something like `[this]() { member_function(); std::cout << member_variable << '\n'; }` – Some programmer dude Feb 05 '23 at 21:34
  • 2
    Pass non-NULL `user_data` to `add_repeating_timer_us`, read out `t->user_data`? Based on [Pi Pico docs](https://raspberrypi.github.io/pico-sdk-doxygen/group__repeating__timer.html) – Hasturkun Feb 05 '23 at 21:36
  • And if you need to store function with a specific signature, you could use [`std::function`](https://en.cppreference.com/w/cpp/utility/functional/function). It can store *any* callable object with the required signature. For the lambda shown in my previous comment it would be `std::function`. – Some programmer dude Feb 05 '23 at 21:36
  • 5
    Do you really want to declare `count` as *static* (i.e. to share one variable named `count` amongst all of the instances of `MyClass`?). If so, you'll need to add a `int MyClass::count = 0;` somewhere into your .cpp file; but if not, you should remove the `static` declaration. – Jeremy Friesner Feb 05 '23 at 21:36
  • 1
    @Sam Varshavchik: I don't think that duplicate close is helpful. – Hasturkun Feb 05 '23 at 21:41
  • Really, @Hasturkun, that duplicate doesn't include a missing definition of a declared static class member? I'm fairly confident that it does. – Sam Varshavchik Feb 05 '23 at 21:45
  • @SamVarshavchik: I'm guessing it's an X Y, User wanted to access a class member. Instead of passing the class as the callback's context/user data, they made a member static and failed to reference it correctly. The undefined reference is a side effect of that, not the primary point. – Hasturkun Feb 05 '23 at 21:47
  • @SamVarshavchik is it helpful as in will someone with the same problem reading the accepted answer of the linked question reach the right answer in finite time? – teapot418 Feb 05 '23 at 21:54
  • My question is not about the error message, but, how do I code the callback? – tomdean1939 Feb 05 '23 at 21:57
  • 4
    Set `user_data` (arg #3 of `add_repeating_timer_us`) to `this` instead of `NULL`. Inside callback take `t->user_data` and cast it to `MyClass *`. Now you have the instance that called the registration and can call methods on it the usual way. – teapot418 Feb 05 '23 at 22:05
  • I've made some minor edits to the question, and will probably post an answer later, assuming this reopens. The answer is basically the same as my comment above suggests, and teapot418's says explicitly, though. – Hasturkun Feb 05 '23 at 22:10

1 Answers1

1

The Pi Pico repeating_timer API allows you to pass a user_data argument when adding a timer (the third parameter to add_repeating_timer_us).

This value is later returned in the user_data member of the struct repeating_timer passed to your callback.

This can be anything you want, e.g. in your case, a pointer to MyClass, so long as you cast it to and from void *.

Hasturkun
  • 35,395
  • 6
  • 71
  • 104