I am new to C++ I come from a C# background. I am creating an Arduino project using c++ using vs code thanks to https://docs.platformio.org/ .
The following code works and turns on my led strip:
main.cpp
#include <Arduino.h>
#include <LedStrip.h>
// pin where led strip is connected
#define LED_STIP_PIN 4
// number of leds in the strip
#define LED_STRIP_COUNT 7
// My wrapper class
LedStrip myLedStripWrapper;
void setup() {
// empty
}
void loop() {
myLedStripWrapper.setup(LED_STRIP_COUNT, LED_STIP_PIN);
// myLedStripWrapper.foo1(); // <<<HERE-1>>>
// wait forever
while (true) {
delay(1);
}
}
LedStrip.h
#include <Adafruit_NeoPixel.h>
class LedStrip
{
public:
Adafruit_NeoPixel strip;
void setup(uint16_t led_count, uint16_t pin)
{
// Declare our NeoPixel strip object:
Adafruit_NeoPixel a(led_count, pin, NEO_GRB + NEO_KHZ800);
strip = a;
// INITIALIZE NeoPixel strip
strip.begin();
strip.show();
strip.setBrightness(15);
foo1(); // <<<HERE-2>>> <------------------- calling foo1 from here turns on the led strip
}
// Color led strip blue
void foo1()
{
uint32_t color = strip.Color(0, 0, 100);
for (uint16_t i = 0; i < strip.numPixels(); i++)
{ // For each pixel in strip...
strip.setPixelColor(i, color); // Set pixel's color (in RAM)
strip.show(); // Update strip to match
// delay(100);
}
}
};
Note that in the code I have labels <<<HERE-1>>>
and <<<HERE-2>>>
. I want to call function foo1
from <<<HERE-1>>>
. Why is it that if I uncomment <<<HERE-1>>>
and comment <<<HERE-2>>>
the code does not work and the LED strip does not turn on? In other words I do not want to call foo1 from within the class wrapper. I am just calling it form there because it only works if I call it form there.
The writers of that class made a grade-school C++ mistake and didn't correctly observe the Rule of Three. This means an Adafruit_NeoPixel
object can be copied when it is not safe to do so.
void setup(uint16_t led_count, uint16_t pin)
{
// Declare our NeoPixel strip object:
Adafruit_NeoPixel a(led_count, pin, NEO_GRB + NEO_KHZ800);
strip = a; // copy here. Both a and strip point to a shared resource
// INITIALIZE NeoPixel strip
strip.begin();
strip.show();
strip.setBrightness(15);
} // a goes out of scope here and frees the shared resource in its
// destructor. Oops.
The easiest fix is to initialize strip
in LedStrip
's constructor where it doesn't need to be copied.
To ensure strip
isn't copied, you're going to have to prevent LedStrip
from being copied or implement special member functions that allow LedStrip
to be copied without copying strip
. In the example below I will simply prevent copying.
If copying is required consider replacing Adafruit_NeoPixel strip;
with std::shared_ptr<Adafruit_NeoPixel> strip;
so a pointer will be copied rather than an object that can turn into a bomb when copied.
class LedStrip
{
public:
Adafruit_NeoPixel strip; // you sure you want this public?
// adding constructor so we don't have to copy a Adafruit_NeoPixel object
LedStrip(uint16_t led_count, uint16_t pin):
strip(led_count, pin, NEO_GRB + NEO_KHZ800) // this is a member initializer list
// It allows us to construct strip
// without having to copy anything.
// more on that later
{
// INITIALIZE NeoPixel strip
strip.begin();
strip.show();
strip.setBrightness(15);
}
// preventing copying of LedStrip
LedStrip(const LedStrip& ) = delete;
LedStrip & operator=(const LedStrip& ) = delete;
// note if the compiler doesn't like the = delete, remove it, make
// the copy constructor and assignment operator private, and do not
// implement them
// Color led strip blue
void foo1()
{
uint32_t color = strip.Color(0, 0, 100);
for (uint16_t i = 0; i < strip.numPixels(); i++)
{ // For each pixel in strip...
strip.setPixelColor(i, color); // Set pixel's color (in RAM)
strip.show(); // Update strip to match
// delay(100);
}
}
private:
/* only needed if the = delete trick above doesn't work.
LedStrip(const LedStrip& );
LedStrip & operator=(const LedStrip& );
*/
};
Then
LedStrip myLedStripWrapper;
becomes
LedStrip myLedStripWrapper(LED_STRIP_COUNT, LED_STIP_PIN);
and
myLedStripWrapper.setup(LED_STRIP_COUNT, LED_STIP_PIN);
vanishes from the world, never to be seen again.