Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overriding #define in libraries

I have created an Arduino Library for a device, of which it can be generally configured in several ways. E.g. use interrupts or poll it. From other examples I have created the following files: foo.h, fooConfig.h and foo.cpp shown below for the library. Where fooConfig.h contains the configuration of how to use the shield. Such as with or without interrupts etc...

In doing so I would like the main sketch's INO file to be able to over-ride default settings, which have been declared using #define's. Including in the library's instance. The results show it really does. At least the way I am doing it.

The below code is a simplified example with the problem:

definetest.ino

#define BAR USE_POLL
#include <foo.h>

foo test;

void setup() {
  Serial.begin(115200);
  delay(1000);

  Serial.print(F("setup's defined BAR was "));
  Serial.println(BAR);

  Serial.print(F("inside foo.begin defined BAR was "));
  Serial.println(test.begin());
}

void loop() {
}

foo.h

#ifndef FOO_h
#define FOO_h

#include "FOOConfig.h"

class foo {
  public:
    int begin();
};
#endif // FOO_h

FooConfig.h

 #ifndef FOOCONFIG_h
  #define FOOCONFIG_h

  #define USE_INT      1
  #define USE_POLL     2

  #ifndef BAR
    //default to using interrupts
    #define BAR USE_INT
  #endif // BAR

#endif  // FOOCONFIG_h

foo.cpp

#include <foo.h>

int foo::begin() {
#if defined(BAR) && BAR == USE_INT
  Timer1.attachInterrupt( isr );  // error here, because of the define...
  return 1;
#elif defined(BAR) && BAR == USE_POLL
  return 2;
#endif
  return 0;
}

Yields the following serial output:

setup's defined BAR was 2
inside foo.begin defined BAR was 1

Where it was desired to have the BAR inside the foo.begin equal to 2, not 1. Noting it is desired to have the precompiler decide to or not omit the attachInterrupt. Don't want the dependancy and consumption of the resources of the library if it is not used. Simply want it to be an advanced option.

I understand this may best handled with a make file or eclipse, but I am trying to publish this library for the Arduino IDE currently at 1.0.3.

Any help is appreciated.

FYI, the real and whole code is here. https://github.com/mpflaga/Sparkfun-MP3-Player-Shield-Arduino-Library/tree/master/SFEMP3Shield

like image 788
mpflaga Avatar asked Jan 19 '13 21:01

mpflaga


2 Answers

Regardless of tool chain, the program does not and should not determine how the library is compiled. A key concept of a library is that it is fully developed, compiled and packaged without the existence of any program. There is a one way dependency: a program depends on the library -- a library has no dependency on any program. A key point that highlights this is that you do not have to distribute source code to use a library. A library can be used with just headers and binary (.a) Take a peek into all the WinAvr libraries that are used.

What you are seeking is how to have multiple configurations of your library. In other tool chains this is readily done at the project level where you can create any number of output configurations. In your case you would have poll and int, and the toolchain would produce two libraries, for example:
libMySomething_int.a
libMySomething_poll.a

Programs choose which configuration of the library they wanted to use.

As noted by others, the Arduino IDE will not provide for this form of complexity. Since you stated you intend to stay within that toolchain, these are solutions I can see:

  1. Make two copies of the library that differ just by the one #define. This is basically you providing the two configurations. Because they differ by a tiny amount, it will be easy to WinMerge between to two and keep codebases synchronized.

  2. Rethink whether it is necessary to have one interface to the two forms. You do not have to have just one begin(), you can have two forms:

    void beginInt();
    void beginPoll();

    void getSomethingInt();
    void getSomethingPoll();

Keep in mind that this does not waste code space. The linker will remove all unused functions from the final program, so if you just use the Int form, all the Poll functions get dropped.

The choice between these two isn't clear and somewhat subjective. The decision should consider what you are intended to encapsulate/hide in the library, and what you want to make clear. If this library was an interface to a variety of real time clock chips, then you would clearly be fair to encapsulate all the differences and provide one set of functions. But in your case you are implying key changes in resource consumption, timing, and concurrency -- I'm not sure it is best to hide this.

like image 124
jdr5ca Avatar answered Sep 27 '22 02:09

jdr5ca


The Arduino IDE compiles libraries individually so you would need to pass the define as a -D option during the compile. The Arduino IDE does not currently provide a facility for you to easily do that. Arduino 1.5 provides some functionality via the boards.txt system but this probably will not provide the flexibility you need.

So, as you say, the options are editing make files in products such as Eclipse or by setting one of the "Defines" project properties (such as "Defines - Project") in Visual Studio Pro.

Or by using the TeensyDuino IDE and adding your own menu. defs to the boards.txt

like image 29
Visual Micro Avatar answered Sep 27 '22 02:09

Visual Micro