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
2 Likes
Is there any tutorial showing me how to setup a local workflow?
ScruffR
December 11, 2017, 7:37am
11