lancaster-university / microbit-dal

http://lancaster-university.github.io/microbit-docs
Other
256 stars 130 forks source link

Registering an EventHandler in a class #406

Closed komodo108 closed 5 years ago

komodo108 commented 5 years ago

Below is an example of the problem, the MicroBit should print "Hi" whenever an action occurs, but is printing nothing.

#include "MicroBit.h"

class test {
    private:
        MicroBit* uBit;
    public:
        test(MicroBit* microbit) {
            uBit = microbit;
            uBit->serial.send("hiii");
            uBit->messageBus.listen(MICROBIT_ID_GESTURE, MICROBIT_EVT_ANY, this, &test::event);
        }

        void event(MicroBitEvent e) {
            uBit->serial.send("Hi");
        }
};

MicroBit uBit;

int main() {
    uBit.init();
    test thetest(&uBit);
    while(true) {}
    release_fiber();
}

I am following the example method from here. Also, adding in more debugging to this, such as adding a print to serial from just above the messageBus.listen() call works.

pelikhan commented 5 years ago

Remove while(true) {}.

komodo108 commented 5 years ago

Sadly, that did not work. Same behaviour as before.

finneyj commented 5 years ago

Really? Did you keep the release_fiber() in there? That call deletes the main thread and releases any associated resources back to the system.

Removing the while(true) loop should be the way to go, or do a uBit.sleep() operation in there while loop (or anything else that blocks). We're running a non-preemtpive scheduler to help keep things simpler for the kids...

finneyj commented 5 years ago

OK - I can reproduce this. Something afoot. Looking into it...

komodo108 commented 5 years ago

@finneyj Sorry for the mistake! I was just following the tutorial from here, I removed changed the loop to: while(true) { uBit.sleep(10000); } and have tried both with and without the call to release_fiber() and there is still no change when moving the MicroBit.

Just saw the second comment, and thank you :)

finneyj commented 5 years ago

Something funky in the MessageBus event handling in this case I think, and/or the lazy instantiation of the gesture recognizer. If you try this (which is really just the same as your code with an addition C style handler, both event handlers trigger for me.)

#include "MicroBit.h"

class test {
    private:
        MicroBit* uBit;
    public:
        test(MicroBit* microbit) {
            uBit = microbit;
            uBit->messageBus.listen(MICROBIT_ID_GESTURE, MICROBIT_EVT_ANY, this, &test::event);
        }

        void event(MicroBitEvent e) {
            uBit->serial.printf("EVT2\n");
        }
};

MicroBit uBit;
test thetest(&uBit);

void allGestures(MicroBitEvent e) {
    uBit.serial.printf("EVT1\n");
}

int main() {
    uBit.init();
    uBit.messageBus.listen(MICROBIT_ID_GESTURE, MICROBIT_EVT_ANY, allGestures);

    while(1)
    {
        uBit.serial.send("Hi\n");
        uBit.sleep(2000);
    }
    release_fiber();
}
finneyj commented 5 years ago

Ahh, OK. I get it. :)

You had test thetest(&uBit); as a local variable in main. This means your class instance would be declared on the stack of the main thread. This could then get paged out, and the instance of your class is therefore not always in memory where you think it is. generally a good idea not to declare anything on the stack of a thread that is accessed outside the given function/method... if that makes sense?

This slight variant on your code works for me:

finneyj commented 5 years ago
#include "MicroBit.h"

class test {
    private:
        MicroBit* uBit;
    public:
        test(MicroBit* microbit) {
            uBit = microbit;
            uBit->messageBus.listen(MICROBIT_ID_GESTURE, MICROBIT_EVT_ANY, this, &test::event);
        }

        void event(MicroBitEvent e) {
            uBit->serial.send("Hi");
        }
};

MicroBit uBit;

int main() {
    uBit.init();
    new test(&uBit);
    release_fiber();
}
komodo108 commented 5 years ago

Thanks so much!