1

I am about to write a custom ESPHome component. I don't have much experience with C language and I am facing some troubles using external library.

For demonstration, I prepared a simple component class..

class Test: public Component {

public:
    auto t = timer_create_default();

    void setup() override {
        ESP_LOGD("TEST", "Test setup called!");
        t.every(1000, TestLog);
    }
    
    void loop() override {
        ESP_LOGD("TEST", "Test loop called!");
        t.tick();
    }
    
    bool TestLog(void *) {
        ESP_LOGD("TEST", "TestLOG!");
        return true;
    }
}

With this, I receive:

In file included from src\main.cpp:32:0: src\Test.h:7:35: error: non-static data member declared 'auto' auto t = timer_create_default();

I took it from some example where they did not have the class, but I can't find out, how to use it.

The library is:

https://github.com/contrem/arduino-timer/

I can still rewrite it without this timer completely and handle it only in the loop function, but I would like to understand what I am doing wrong.

If I change the return type to Timer<> I got another error:

src\Test.h: In member function 'virtual void Test::setup()': src\Test.h:11:24: error: no matching function for call to 'Timer<>::every(int, )'
t.every(1000, TestLog);

Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
Ondrej Havlicek
  • 170
  • 5
  • 12

1 Answers1

1

You can not use auto to declare non-static member variables so you need to replace auto with the type returned by timer_create_default().

If you are not sure what type it returns, you can simply use decltype in the declaration:

decltype(timer_create_default()) t = timer_create_default();

If I read the code in the repo correctly, the returned type is Timer<>, so this should also work:

Timer<> t = timer_create_default();

or simply:

Timer<> t;

Also: The function pointer passed to t.every() should be a bool (*)(void*) but TestLog is a non-static member function and the pointer type is bool (Test::*)(void*) - You can fix that by making TestLog static:

class Test: public Component {
public:
    // ...

    static bool TestLog(void *) {
        ESP_LOGD("TEST", "TestLOG!");
        return true;
    }
};

If you want to get the Test instance in the TestLog callback, make the Timer

Timer<TIMER_MAX_TASKS, millis, Test*> t;

and change TestLog:

class Test: public Component {
public:
    // ...

    static bool TestLog(Test* t) {
        ESP_LOGD("TEST", "TestLOG!");
        return true;
    }
};

and in setup():

t.every(1000, TestLog, this);

You'll now get a pointer to the Test instance in the TestLog callback and you can use this to call a non-static member function in Test.

Full example:

class Test : public Component {
public:
    Timer<TIMER_MAX_TASKS, millis, Test*> t;

    void setup() override {
        ESP_LOGD("TEST", "Test setup called!");
        // call the static member function every second:
        t.every(1000, TestLogProxy, this);
    }
    
    void loop() override {
        ESP_LOGD("TEST", "Test loop called!");
        t.tick();
    }

    bool TestLog() {
        ESP_LOGD("TEST", "TestLOG!");
        return true;
    }
    
    static bool TestLogProxy(Test* t) {
        // forward the callback call to the non-static member function:
        return t->TestLog();
    }
};
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
  • Oh, I forgot to write that I tried that already... but I got another error message: src\Test.h: In member function 'virtual void Test::setup()': src\Test.h:11:24: error: no matching function for call to 'Timer<>::every(int, )' t.every(1000, TestLog); – Ondrej Havlicek Jul 28 '22 at 11:41
  • @OndrejHavlicek That's unrelated to the problem you've asked a question about. The solution to the problem you asked about is in my answer. It seems you call `t.every(1000, TestLog);` in `setup()` but `every` does not have an overload accepting those parameters. – Ted Lyngmo Jul 28 '22 at 11:43
  • @OndrejHavlicek Is `TestLog` a `handler_t` instance? – Ted Lyngmo Jul 28 '22 at 11:49
  • Thanks a lot for the support ;) But I need somehow to get this code working in general. Do you see why the method TestLog is not visible/usable? Or do You think I should create a new question? – Ondrej Havlicek Jul 28 '22 at 11:50
  • Ups, IDK, how to check if it is? – Ondrej Havlicek Jul 28 '22 at 11:51
  • @OndrejHavlicek I updated the answer to take care of that. When it comes to making the code work in general: Stackoverflow isn't the place to ask for collaborations on projects. You here should ask one specific question, [accept answers](https://stackoverflow.com/help/someone-answers) that solves the problem and then move on. If you have more questions, you can ask them one at a time as your project evolves. – Ted Lyngmo Jul 28 '22 at 12:01