0

I am using the FastLED library in my program and the basic usage is that the following lines go at the top of the main sketch:

#include <FastLED.h>
#define NUM_LEDS 60
#define DATA_PIN 6

You can see the documentation at https://github.com/FastLED/FastLED/wiki/Basic-usage

However, I am using the FastLED library in several different objects in my program and I would like to be able to reference NUM_LEDS in different header files for each object so that the number of LEDS can be controlled just by changing the value in the main sketch.

I am also intending that my own objects can be made into libraries for others to use, so they will then define the settings in their main sketch, that my libraries will then use.

Rob Hilken
  • 142
  • 1
  • 2
  • 11
  • Sure.. Create a header file containing those three lines (call it, for instance, FastLedInclude.h) and then, in each file you need the FastLed library, write #include "FastLedInclude.h" instead of #include <FastLed.h> – frarugi87 Mar 18 '16 at 12:32
  • This won't work as someone using my library in their own fastLED sketch won't then be able to define their own size of project from the main sketch. I'll alter my question to make sure that is understood. – Rob Hilken Mar 18 '16 at 12:34
  • You will need to have NUM_LEDS defined in every file you compile; that's why you need it in a header file to be included by every cpp or ino file. Now, if you want to make a library, that file should either be in 1) the library folder, or 2) the sketch folder. The second approach is, IMHO, very bad, since it requires the user to create the file in its sketch folder and requires the library to know where the sketch is, which is against the definition of "library", i.e. a piece of code that can work by itself. My personal advice is to ask the user to modify the library file or, if you don't want – frarugi87 Mar 18 '16 at 12:45
  • to force/allow him to modify your files, edit the code using dynamic allocation instead of compile-time static allocation. I mean, instead of defining DATA_PIN you can store a uint8_t variable in your class containing the data pin. You can do the same with NUM_LEDS, and then allocate the matrix dynamically (with mallocs or news) in the code. It can have lower performances, but it will work better – frarugi87 Mar 18 '16 at 12:47
  • That's very helpful. I wonder if I could I ask the user to add const byte numberOfLeds = NUM_LEDS to their sketch and then use numberOfLeds in my library rather than NUM_LEDS ? – Rob Hilken Mar 18 '16 at 12:56
  • and then add a pointer to const byte numberOfLeds in my library header? – Rob Hilken Mar 18 '16 at 13:03
  • Well, your library will contain at least one class, won't it? Consequently you can store the variable in your class, then either make it public (bad) or private (better) and set it in the constructor. So the user will have to allocate your object dynamically yourclass *obj = new yourclass(60); (or, if he defined #define NUM_LEDS 60, he can write yourclass *obj = new yourclass(NUM_LEDS );) or statically yourclass obj(60); (or yourclass obj(NUM_LEDS );). In either case you will have the value stored in your object – frarugi87 Mar 18 '16 at 13:08
  • This is very helpful, many thanks. I tried to implement the #include "FastLedInclude.h" version that you first suggested and I realised that I didn't give all of the information in the question. The FastLED setup also needs me to add struct CRGB leds[NUM_LEDS]; into pages where the code is used. If I include that in FastLedInclude.h then I get a compile error multiple definition of 'leds' – Rob Hilken Mar 18 '16 at 13:14
  • I have tried using struct CRGB leds[NUM_LEDS]; in the main sketch and extern CRGB *leds; in my cpp files and it compiles but the program does not work – Rob Hilken Mar 18 '16 at 13:14
  • Of course you can't DEFINE a variable in a header, otherwise you can happen to define it more than once. You definitely can DECLARE it, and you should declare it extern, then define it in only one cpp or ino file. The usual way is to 1) write extern struct CRGB leds[]; in the FastLedInclude.h file. 2) choose a ino or cpp file (probably the main ino file is not the most indicated, but should work) and write struct CRGB leds[NUM_LEDS];. If this does not work, post your code and I'll try to have a look at it – frarugi87 Mar 18 '16 at 13:27
  • This works perfectly! Thank you so much for your assistance, feel free to contribute this as an 'answer' – Rob Hilken Mar 18 '16 at 13:34
  • I added the answer with some more examples.. – frarugi87 Mar 18 '16 at 15:31

1 Answers1

1

As the OP suggested, I'm posting a summing up of the comments under his question since the answer was found.

In order to make a common define for those parameters in different source files, the easiest solution is to make a shared header. To do this, just create a new file called FastLedInclude.h and, inside of that, write

#include <FastLED.h>
#define NUM_LEDS 60
#define DATA_PIN 6

Then in every source file you will just have to #include "FastLedInclude.h" to be able to use that library.

The FastLED library also requires the programmer to create a struct. Now, placing the definition of the struct (i.e. struct CRGB leds[NUM_LEDS];) into the header file leads to compilation errors, since the compiler writes the code to allocate it once for every object file.

The correct way to share this among different object files is to declare it extern in the header, then define it just once in one of the cpp or ino files:

// into FastLedInclude.h
extern struct CRGB leds[];

// into any cpp or ino file (but just once)
struct CRGB leds[NUM_LEDS];

This can also be done in the main ino sketch file, but personally I prefer to define it into another one (it depends, however, on how you choose to divide the program).

If you want to create a library, some other problems arise. The easiest solution is to ask the user to manually modify the header file which will be in the library folder. This solution is a bit uncomfortable, but it is the safest one.

Another solution is to force the user to create a header file into the sketch folder. Then the library should know the sketch folder path to back-include it. But.. This is a very discouraged option, since it will require the library to know the sketch location, thus violating the consistency principle at the base of a library-based approach.

The third solution is to modify the approach, from a compile-time static definition to a dynamic one. In order to do this, instead of defining NUM_LEDS and DATA_PIN at compile time you save them as variables in the library class.

For instance, in your library class definition you have

class yourclass
{
    public:
        yourclass(uint8_t data_pin, uint8_t num_leds);
        ~yourclass();
    private:
        uint8_t _data_pin;
        uint8_t _num_leds;
        struct CRGB *leds = NULL;
};

And the implementation can be

yourclass::yourclass(uint8_t data_pin, uint8_t num_leds)
{
    _data_pin = data_pin;
    _num_leds = num_leds;

    // Dynamic allocation of the array
    leds = (struct CRGB *) malloc(num_leds * sizeof(struct CRGB));
}

yourclass::~yourclass()
{
    // you should free the leds array when done
    free(leds);
}

Then the user can write

yourclass *obj = new yourclass(6, 60);

// or, if he wants to define,
#define NUM_LEDS 60
#define DATA_PIN 6
...
yourclass *obj = new yourclass(DATA_PIN, NUM_LEDS);

or, in the case of a statically allocated object,

yourclass obj(6, 60);

// or, if he wants to define,
#define NUM_LEDS 60
#define DATA_PIN 6
...
yourclass obj(DATA_PIN, NUM_LEDS);
frarugi87
  • 2,721
  • 10
  • 19