0

The development for embedded system impose an other way to code. In the goal to minimize size of my library named RF24Wave, I would adapt the structure of my main class. The idea is to declare some functions only with the presence of certain #define during the inclusion of my library in main program.

The popular library, like MySensor use this way to minimize memory footprint.

So, I have two files for my library :

  • RF24Wave.h : header file which contain function declarations
#ifndef __RF24WAVE_H
#define __RF24WAVE_H

#include <arduino.h>

...

class RF24Wave
{
  public:
  /****** Common functions ******/
    void begin();
#if !defined(WAVE_MASTER)
  /****** Node functions ********/
    void connect();
#else
  /****** Master functions ******/
    void printNetwork();
#endif
  private:
    bool synchronized = false;
}
  • RF24Wave.cpp: source file which contain function definitions
#include "RF24Wave.h"

void begin()
{
  //Body of my function
}
#if !defined(WAVE_MASTER)
void connect()
{
  //Body of my function
}
#else
void printNetwork()
{
  //Body of my function
}
#endif

Secondly, I include this library in my main sketch named master.cpp, with #define WAVE_MASTER:

  • master.cpp: main sketch
#include <RF24.h>
#include <RF24Network.h>
#include <RF24Mesh.h>
#include <SPI.h>
#define WAVE_MASTER
#include <RF24Wave.h>

#include "master.h"

// Configure the chosen CE, CSN pins
RF24 radio(CE_PIN, CSN_PIN);
RF24Network network(radio);
RF24Mesh mesh(radio,network);
RF24Wave wave(network, mesh);

uint32_t displayTimer = 0;

void setup()
{
  Serial.begin(115200);
  wave.begin();
}

void loop()
{
  wave.listen();
  wave.printNetwork();
}

The goal is to include only master functions when #define WAVE_MASTER is defined in the main sketch.

However, during the compilation of my main sketch, I have a linking error

In function `main':
undefined reference to `RF24Wave::printNetwork()'
collect2: error: ld returned 1 exit status
*** [.pioenvs/uno/firmware.elf] Error 1

I compiled with PlaformIO Core 1.7.1 /Atom 1.13.0

Finally, the reason of this problem is the scope of #define.

The solution of this problem is added build flags to gcc-compiler !

If you use combo PlatformIO/Atom, you can add this line into this config file platformio.ini :

  • build_flags = -D$NAME_DEFINE

In our case :

  • build_flags = -DWAVE_MASTER

After adding this line, the building seems work fine !

In addition, with this selective #define, my library has reduced footprint memory more than 10% !

Many thanks for your help.

alambrec
  • 3
  • 1
  • 3
  • where is WAVE_MASTER defined for "master.cpp"? This will not work, because you cannot control the defines for your code file. (except you use a compiler option for this, if available) – robin.koch Jan 25 '17 at 14:01
  • Arduino is definitively not C and not exactly C++. – too honest for this site Jan 25 '17 at 14:03
  • 1
    Possible duplicate of [What is an undefined reference/unresolved external symbol error and how do I fix it?](http://stackoverflow.com/questions/12573816/what-is-an-undefined-reference-unresolved-external-symbol-error-and-how-do-i-fix) – too honest for this site Jan 25 '17 at 14:04
  • @robin.koch Thx for your answer ! WAVE_MASTER is defined for "master.cpp" at the top file. But you are right concerning the scope of `#define`. I'm not sure that the first `#define WAVE_MASTER` in `master.cpp` is taken into account during the compilation of source file `RF24Wave.cpp`. – alambrec Jan 25 '17 at 15:50

2 Answers2

1

If you add your library in the arduino IDE as it is described here it just consists in linking another project to your library functions. It's not a static library (see static and dynamic libraries). Then I think it's not necessary to worry about its size since the compiler will embed your library functions only if you use them.

Try opening any example (AnalogReadSerial), compile it. Then Sketch->Add a library->SPI. Compile it again, the size does not change. Try to call SPI.begin() in the setup function, the size increases. Add a call to SPI.setBitOrder(MSBFIRST);, the size increases again. Add another call to SPI.setBitOrder(MSBFIRST);, the size increases again, but not by the same amount since it contains only one setBitOrder definition and two calls to the setBitOrder function.

That's not exactly true for all libraries since some constructs could force the compiler to embed some code or allocate memory even if the variable is not used (see for instance volatile variables).

So regarding your size issue, you'd probably only need to use one #define MASTER, write the master code in setup and loop functions surrounded by #ifdef MASTER and the slave code surrounded by #else...#endif. The compiler will include the function definitions that both master or slave use.

Community
  • 1
  • 1
Emilien
  • 2,385
  • 16
  • 24
0

So, with your answer, I found the solution ! The problem is the scope of #define. During the building, the first source code compiled is the main sketch ! So, it includes the correct #define WAVE_MASTER in RF24Wave.h of master.cpp. But, the compiler don't take this define into account of other source files. So, during the compilation of RF24Wave.cpp, #define WAVE_MASTER wasn't defined for this source file.

The solution consist to add an extra gcc-flag to define WAVE_MASTER for all source and header files.

With PlatformIO/Atom, it's possible in adding this line in config file platformio.ini

  • build_flags = -DWAVE_MASTER

Finally, your config file should look like this :

[env:uno]
platform = atmelavr
board = uno
framework = arduino
build_flags = -DWAVE_MASTER

With this solution, it is no longer necessary to add #define WAVE_MASTER in your header file, because this is the compiler which add it for you.

In addition, this optimization has been reduced more than 10% memory usage, because like this is a big class object, the compiler builded all functions. With selective define, the compiler will build only useful functions.

alambrec
  • 3
  • 1
  • 3