Project compiles, but won't work if I add a param in a subclass constructor

Hi. I’m having a very specific issue, and really obscure as well. If I add a second param to a subclass, program compiles and uploads to NodeMCU ESP32, but it doesn’t work properly.

Basically, I have a set of animations for an Adafruit Ring, and I’m using FastLed to create them.

I’m working with platformio v5.0.2b1, using CLion 20.04, and the toolchain for Clion is MinGW.

Anyway, the issue I’m about to tell you occurs even if I compile using Arduino IDE.

Basically, animations are polymorphic, and I’m kinda using the Strategy pattern to pass the animations to the led ring object I created.

Code structure is quite simple. Apart from the strategy pattern I’m using Adapter to wrap and decouple Fastled.

You can see the code structure here. It’s working, but not using Leds (only strings):
https://repl.it/repls/MeagerPrivateBoard#main.cpp

So problem is: whenever I add a second parameter to the constructor of a given animation (meaning, to a subclass of Animation class), the program compiles, but the animation stops working. Ring stays off (no lights at all)

FYC:
#pragma once

#include <FastLED.h>
#include "Animation.h"
#include "Ring.h"

class PlainColorAnimation : public Animation {
public:
    PlainColorAnimation(Ring &aRing)
            : Animation(aRing) {}

    void execute() override {
        ring.fill(Ring::colors["yellow"]); // TODO: make this dynamic by receiving a color param
    }
};

Check now this. What I try to do, I try to add a second parameter (just like you can see in the working code I linked before). So:

PlainColorAnimation(Ring &aRing, CRGB aColor = CRGB::Green)

Just that, I’m not even setting aColor value to a member variable, and that param causes the animation to fail. Meaning, no lights will display, and… Serial console will display garbage (I think this may be important).

I wondered why the Repl example worked fine. It’s not a problem with polymorphism, is it? So, I discovered Repl uses c++17 and I had c++11. So…, I bumped my version adding some lines in my ini file.

FYC:
[esp32]
; upgrade XTensa32 GCC/G++ compiler to 8.2.0
; use bleeding edge arduino-esp32
platform_packages =
; toolchain-xtensa32 @ 2.80200.200226 ← this line here is maybe needed by fails in windows 10
framework-arduinoespressif32 @ GitHub - espressif/arduino-esp32: Arduino core for the ESP32

[common]
build_flags =
; do not redefine arduino
;    -DARDUINO=10800
    -DESP32=1
    -DARDUINO_ARCH_ESP32=1
    -DBOARD_HAS_PSRAM
    -std=c++17
; only use C++17 now not GNU++17. This is an either-or relation.
;    -std=gnu++17
build_unflags =
    -std=gnu++11


[env:nodemcu-32s]
platform = espressif32@1.12.4
board = nodemcu-32s
framework = arduino
lib_deps = fastled/FastLED@^3.3.3
lib_ldf_mode = off
upload_port = COM5
platform_packages =
    ${esp32.platform_packages}
build_flags =
    ${common.build_flags}
build_unflags =
    ${common.build_unflags}

I’ve got that code from here:

Problem persist :frowning:

Any clue?

I don’t see any problems with the code or the execution on my ESP32. After copying all your files from the REPL example and changing the main.cpp to

#include <Arduino.h>
#include <iostream>
using namespace std;

#include "animation.h"
#include "plainColorAnimation.h"  
#include "rainbowAnimation.h"  
#include "ring.h"

Ring ring{};
Animation* plainGreenColor = new PlainColorAnimation(ring, "green"); 
Animation* rainbow = new RainbowAnimation(ring);   
Animation* plainBlueColor = new PlainColorAnimation(ring, "blue"); 
  
///////////////////// Test code
void setup() {
  Serial.begin(115200);
  Serial.println("Beginning of firmware!!");
  Serial.flush();
  ring.draw(plainGreenColor);

  std::cout << "\n";

  ring.draw(rainbow);

  std::cout << "\n";

  ring.draw(plainBlueColor);
}

void loop() { }

my ESP32 outputs on reset

Beginning of firmware!!
- It's all green now!
0 green 
1 green 
2 green 
3 green 
4 green 
5 green 
6 green 
7 green 
8 green 
9 green 
10 green 
11 green 
12 green 
13 green 
14 green 
15 green 
16 green 
17 green 
18 green 
19 green 
20 green 
21 green 
22 green 
23 green 

- Rainbow, ujuuu!
0 blue 
1 blue 
2 blue 
3 blue 
4 blue 
5 blue 
6 blue 
7 green 
8 green 
9 green 
10 green 
11 green 
12 green 
13 yellow 
14 yellow 
15 yellow 
16 yellow 
17 yellow 
18 yellow 
19 orange 
20 orange 
21 orange 
22 orange 
23 orange 

- It's all blue now!
0 blue 
1 blue 
2 blue 
3 blue 
4 blue 
5 blue 
6 blue 
7 blue 
8 blue 
9 blue 
10 blue 
11 blue 
12 blue 
13 blue 
14 blue 
15 blue 
16 blue 
17 blue 
18 blue 
19 blue 
20 blue 
21 blue 
22 blue 
23 blue 

Which looks all good to and is also the same output in the REPL.

And that is with the constructor being

PlainColorAnimation(Ring& aRing, string aColor = "blue")
    : Animation(aRing), color(aColor) {};

already. If I change it to e.g.

  PlainColorAnimation(Ring& aRing, string aColor = "blue", int someOtherDefault=123)
    : Animation(aRing), color(aColor) {};

I get the same exact output.

And that is all with the basic platformio.ini of

[env:esp32]
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200

No fancy compiler overwrites, not using an outdated ESP32 platform version. Just the defaults, which work perfectly fine.

So I can only suggest to

  1. use the same platformio.ini and retry
  2. double check that your sketch implements setup() and loop() and not main() as in the desktop variant
  3. upload the exact PlatformIO project folder and code that has the problem.

Thanks a lot for trying the code and taking the time to test it in a real env.

I tried with you simple ini file

[env:nodemcu-32s]
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200

I’m not sure about the board, but works fine

board = esp32dev instead of nodemcu-32s

And yes, I’m using Arduino framework and no any other. I have setup and run working properly.

I found the issue. It wasn’t as obscure as I thought! I just seems like I don’t know how to use dictionaries (?

So, this wasn’t working:

class PlainColorAnimation : public Animation {
public:
    PlainColorAnimation(Ring &aRing, CRGB aColor = Ring::colors["green"])
            : Animation(aRing), color(aColor) {}

    void execute() override {
        ring.fill(Ring::colors["blue"]); <-- this code from dictionary works fine, btw
    }
private:
    CRGB color;
};

But changed the CRGB aColor = Ring::colors["green"] to CRGB::Yellow works now

Believe me I spended the entire day trying to make things works. I’m so not used to c++, I this one was bugging me a lot.

Thanks again for your feedback.

So, I’ll google and find out why this piece of code won’t work when used as param (but it does used in other contexts)

// .h

class Ring {
public:
    ...
    typedef std::map<std::string, CRGB> ColorMap;
    static ColorMap colors;

};

// .cpp

Ring::ColorMap Ring::colors = {
        {"blue",   CRGB::Blue},
        {"green",  CRGB::Green},
        {"red",    CRGB::Red},
        {"yellow", CRGB::Yellow},
};