Inheritance and Polymorphism on Teensy 3.2

Status
Not open for further replies.

Dividinho

New member
Hi there,
I am currently working on an Infinity Mirror Clock project.
I want to refactor my code and implement a State Pattern for which I need polymorphism.

This is my interface class for the states:
#ifndef state_h
#define state_h
#include "InternalState.h"

class stateInterface {
public:
virtual void midButtonPress(InternalState& anIS) = 0;
virtual void loopAction(InternalState& anIS) = 0;
};
#endif

---------------------------------------------------------------

This is my first concrete state:
#ifndef displayTime_state_h
#define displayTime_state_h

#include "stateInterface.h"
#include "InternalState.h"

class displayTime_state : public stateInterface {
public:
void midButtonPress(InternalState& anIS) {
.... concrete Implementation ....
}

void loopAction(InternalState& anIS) {
.... concrete Implementation ....
}
};

#endif

---------------------------------------------------------------

And in the running class I have:
[...]
#include "InternalState.h"
#include "stateInterface.h"
#include "displayTime_state.h"

class Clock {
private:
InternalState _iS;
stateInterface *externalState;

public:
[...]
void setup(){
[...]
externalState = new displayTime_state();
}

void ISR_MidButton() {
[...]
externalState->midButtonPress(_iS);
}


I have noticed the following:
After the upload on the Teensy it takes ≈ 30 seconds until my program starts running.
When I enter the ISR_MidButton() method, my clock stops working and freezes. (That means externalState->midButtonPress(_iS); is not getting called properly)
Everything works fine, as soon as I remove the inheritance :) public stateInterface) and change the type of *externalState to displayTime_state.
Unfortunately I need the inheritance for what I want to implement.

Do you have any ideas what I might be doing wrong?

Greetings, Divi
 
The Print and Stream classes uses polymorphism with abstract base classes, so maybe look at those for an example. USBHost_t36 does this too, with an abstract class for its USB device drivers, but if you have Teensy 3.2 you can't run that. It needs the 3.6 hardware. Still, the code might be worth a look if Print.h & Stream.h don't help.

Teensy does indeed run your program quickly at startup. To confirm, try turning on the LED early. The startup stuff has a 300 ms delay, so if you turn on an LED early, you should see it light up about 1/3 of a second after power is applied or after the bootloader reboots to run your program.

A common gotcha is too much code in constructors, especially anything that calls functions from any other class. If you have static instances, this is called the "C++ static initialization order fiasco". The best solution used by many Arduino libs is to only initialize class member variables in the constructor and have a begin() function which does the real initialization. Another option is to use constexpr on your constructor, which pretty much enforces that style but also allows the compiler to understand it and optimize the code.

If you're still stuck, try posting a complete (and hopefully minimal) program that anyone can run on a Teensy to see the problem. We're much better at helping when we can see the complete program and have a way to reproduce the problem.
 
Thank you for the reply.
Where can I find Print.h and Stream.h? I am using a Mac and couldn't find them so far. I can also switch to Windows if that helps.
For now I don't think that the constructors are a problem, but I will keep an eye on that.
I will try to reproduce the problem in a smaller scale and post it here.

Thanks for now :)
 
On windows it is installed here :: T:\arduino_1.8.5_142\hardware\teensy\avr\cores\teensy3\Stream.h and T:\arduino_1.8.5_142\hardware\teensy\avr\cores\teensy3\Print.h
If you can locate the Mac install path I expect it will be similar ...\hardware\teensy\avr\cores\teensy3\
 
Thank you.
I now created a smaller example for polymorphism, which DOES work on the same setting:

class base {
public:
virtual void show() = 0;
};

class concreteBlue : public base {
public:
virtual void show(){
setKnobLamp(0, 0, 0, 255);
setKnobLamp(1, 0, 0, 255);
setKnobLamp(2, 0, 0, 255);
}
};

class concreteRed : public base {
public:
virtual void show(){
setKnobLamp(0, 255, 0, 0);
setKnobLamp(1, 255, 0, 0);
setKnobLamp(2, 255, 0, 0);
}
};

class concreteGreen : public base {
public:
virtual void show(){
setKnobLamp(0, 0, 255, 0);
setKnobLamp(1, 0, 255, 0);
setKnobLamp(2, 0, 255, 0);
}
};

base *myState;

void setup() {
// put your setup code here, to run once:
for(int i = 0; i < 9; i++){
pinMode(pins, OUTPUT);
}
for(int i = 0; i < 9; i++){
analogWrite(pins, 0);
}

}

void loop() {
myState = new concreteRed();
myState->show();
delay(1000);
myState = new concreteGreen();
myState->show();
delay(1000);
myState = new concreteBlue();
myState->show();
delay(1000);
}

// setKnobLamp is basically just setting an RGB LED.

Unfortunately the other issue in my main program remains, even though I simplified the state-classes:

class IState {
public:
virtual void midButtonPress() = 0;
virtual void loopAction() = 0;
};

class displayTime_state : public IState {
public:
virtual void midButtonPress() {
Serial.println("display_Time_midButton");
}

virtual void loopAction() {
Serial.println("display_Time_loopAction");
}
};

I also figured out, that my program stops exactly before the function call.
Serial.println("entering method");
externalState->midButtonPress();
Serial.println("exited method");
// this only prints "entering method"


The only difference to the first (working) example is, that externalState->midButtonPress(); is called from within another class and not from the .ino file, which shouldn't make a difference?
 
Update

I finally figured it out.
The function (lets call it "func1"), that is calling "externalState->midButtonPress(_iS);" is part of class "A".
However this func1 was called by an ISR.
I read here: http://forum.arduino.cc/index.php?topic=171219.0 that ISRs only know variables of global context.
The ISR knew class A, because it was global. However it somehow couldn't access externalState, because class A was only holding a pointer to that object.

I will now create a global Array of all the possible states. That way I can then reference the elements of that Array in class A. And since they are now global, the ISR runs as expected.

-------------

I am still not completely sure, why the ISR can't deal with the first case. Do you have a better explanation, why the pointer in class A is not enough for the ISR to just call the function?
 
Status
Not open for further replies.
Back
Top