Strange behaviour with bool

I have a very simple code like below

class OpenOperation {
  public:

    OpenOperation() {
        _timer = new Timer(1000, (void (*)())&OpenOperation::callback);
        classVar = false;
    }

    void start() {
        if (!isRunning()) {
            _timer->reset();
        }
    }

    void stop() {
        _timer->dispose();
    }

    bool isRunning() {
        return _timer->isActive();
    }

  private:
    Timer* _timer;
    volatile bool classVar;
    
    void callback(void) {
        bool localVar = true;
        Serial.print("localVar: ");Serial.println(localVar);
        Serial.print("classVar: ");Serial.println(classVar);
    }
};

OpenOperation openOperation;

void setup() {
    Serial.begin(9600);
    openOperation.start();
}

void loop() {

}

So I basically want to have a instance bool flag. But in console, I see

localVar: 1
classVar: 72

The classVar has a value of 72. It is not true(1) or false (0) and i don’t know where the value comes from.

Can anyone help me to debug this problem?

why is classVar volatile?

I believe that function calls to a volatile object must also be declared volatile.

I remove volatile and still receive the same output.

Also try to ad volatile to the callback function, same output.

Try to change classVar to uint8_t and set its value to 0 in constructor, same output.

This drives me crazy.

If you add some sytax error in your code you will see this warning

 warning: converting from 'void (OpenOperation::*)()' to 'void (*)()' [-Wpmf-conversions]

And this gives away the reason.
The way I see it is that the Timer callback assumes a “normal” function and hence a global offset of classVar which in fact is a non-static field of the object.

You can print out the absolute address of classVar from within the Timer callback and on the other hand add a method to your class that prints the address of this->classVar

To use a non-static member function as Timer callback you’d need to use this constructor

    Timer(unsigned period, void (T::*handler)(), T& instance, bool one_shot=false) : Timer(period, std::bind(handler, &instance), one_shot)

Thank @ScruffR.
I changed the code to

`_timer = new Timer(1000, (void (*)())&OpenOperation::callback, *this);`

I got compilation error

`tempclass.ino:5:81: no matching function for call to 'Timer::Timer(int, void (*)(), OpenOperation&)'`

OK

_timer = new Timer(1000, &OpenOperation::callback, *this);

does work.

I get the correct value in console now.

Thank you.

When you click the SHOW RAW button you get some more info in the following notes to an error message

dummy.ino:5:77: note: candidates are:
In file included from ./inc/application.h:59:0,
                 from src/dummy.cpp:1:
../wiring/inc/spark_wiring_timer.h:38:5: note: template<class T> Timer::Timer(unsigned int, void (T::*)(), T&, bool)
     Timer(unsigned period, void (T::*handler)(), T& instance, bool one_shot=false) : Timer(period, std::bind(handler, &instance), one_shot)
     ^
../wiring/inc/spark_wiring_timer.h:38:5: note:   template argument deduction/substitution failed:
dummy.ino:5:77: note:   mismatched types 'void (T::*)()' and 'void (*)()'
In file included from ./inc/application.h:59:0,
                 from src/dummy.cpp:1:
../wiring/inc/spark_wiring_timer.h:33:5: note: Timer::Timer(unsigned int, Timer::timer_callback_fn, bool)
     Timer(unsigned period, timer_callback_fn callback_, bool one_shot=false) : running(false), handle(nullptr), callback(std::move(callback_)) {
     ^
../wiring/inc/spark_wiring_timer.h:33:5: note:   no known conversion for argument 3 from 'OpenOperation' to 'bool'
../wiring/inc/spark_wiring_timer.h:27:7: note: Timer::Timer(const Timer&)
 class Timer
       ^
../wiring/inc/spark_wiring_timer.h:27:7: note:   candidate expects 1 argument, 3 provided

So how about this?

        _timer = new Timer(1000, &OpenOperation::callback, *this, false);

Is there a Show Raw button in Particle Dev IDE?

Uhm, no - I thought you are using Web IDE. But for desktop I’d go for CLI which provides you with the full error output. Particle Dev is know for keeping things in the dark :wink:

2 Likes

Is there any tutorial showing me how to setup a local workflow?

You can look here
https://docs.particle.io/reference/cli/