2

I'm creating an Arduino library and have 3 files - a "test.ino" program, and two library/class files: "testLibrary.h" and a "testLibrary.cpp".

The library makes use of some hardware-specific resources such as registers and ISRs that depend upon which I/O pin is used, and this should be done at compile time.

I would like to #define a pin number in the main program which, at compile time, is used in the library to determine which code sections are activated. Since this will be a standard Arduino library for use by others, it should compile and run without users having to change their compiler or #include path to make it work.

But it seems that the scope of #define in the main program/sketch does not extend to the library.

test.ino

#define PIN_NUMBER 3
#include "testLibrary.h"
void setup() {}
void loop() {}

testLibrary.h

#ifndef _TESTLIBRARY_h
#define _TESTLIBRARY_h
#ifndef PIN_NUMBER
#error PIN is not defined
#endif
class test {
public:
  test();
  ~test();
};
#endif

testLibrary.cpp

#include "testLibrary.h"
test::test(){}*
test::~test(){}

Compiling the above branches to "#error" using the Arduino IDE 1.8.13 and also using Visual Studio with Visual Micro.

Is there a way for me to have an Arduino library use a "#define" from the main sketch?

Zanshin
  • 61
  • 5
  • You actually didn't define PIN_NUMBER in your code. Or is that a copy&paste error? – chrisl Feb 09 '21 at 07:18
  • You have two #endif but only one #if in testLibrary.h. This will cause a compilation error if you define PIN_NUMBER in your main code (test.ino) when it skips the #error in testLibrary.h. Maybe you did not notice the #endif without #if error? You can fix it by inserting #define _TESTLIBRARY_h as the first line of testLibrary.h. I.o.w. the scope of PIN_NUMBER will be global if you define it in test.ino. Try it. – StarCat Feb 09 '21 at 07:54
  • It was indeed a copy-and-paste error, I put the first line of my code on the same line as the code-tags which meants that for each of my code snippets the first lines were missing. I've corrected that (@chrisl & StarCat) – Zanshin Feb 09 '21 at 09:30
  • You can use a library header file in more than one other libraries or applications. So the library header files should not be dependend on where they were used. Even if the preprocessor would allow defined local macros in included (header) files, it would be a very bad design. How can you know what the main app will do? That leads to horror errors for people using your lib. If you need the value in the class, just add a property to the class and set it in the main code by your constant. The SoftwareSerial library does that to define the tx and rx pins for example. – Peter Paul Kiefer Feb 09 '21 at 09:51
  • 4
    Is there a special reason, why you want to use a define? The convention is to let the user provide such information as parameters for either the class constructor or the begin() method. – chrisl Feb 09 '21 at 11:14
  • Since any pin on the Arduino can be used, I would need to define each and every INT or PCINT "ISR" in the library even though only one is needed, and that would preclude them being used elsewhere. Hence my wish of using a precompiler statement; if this value is passed as a parameter at runtime for this application it is too late. – Zanshin Feb 09 '21 at 18:12
  • does it work if you get rid of the cpp file (rename to .cpp.old)? I had to put a full library's code in the H file to get it recognizing defines before #including it. Works fine since the header file is just literally inserted into the ino at the point of the #include statement. Normally, code in the header is frowned up because it's easy to insert it more than once, but ino files are all concat'd together anyway, so there's no chance of that. Used in this way, it's just like pasting an extra ino file atop your sketch and works quite intuitively. – dandavis Feb 09 '21 at 19:26
  • put another way: the error stems from testLibrary.cpp, not the header file, because as a different translation unit, the ino's macro isn't defined; it has to work as though the ino doesn't exist and the cpp and h file have all they need. afaik, there's simply no way to "pass" a value from an ino to a lib's cpp file. – dandavis Feb 09 '21 at 19:37
  • Thanks for all the replies. I had feared as much, as the c++ documentation did lead me to see that the scope of a "#define" is limited. @dandavis. In the end I am going to use the "BADISR_vect" as a catch-all and assume that the only undefined interrupt is the INTx or PCINTx for the pin, which will be passed to the library as part of a "begin()" call at runtime. And instead of a compact series of "#define" statements that are computed at compile-time I'll have to use a more lengthy "switch(pin)" statement at runtime. – Zanshin Feb 10 '21 at 07:26

1 Answers1

2

The scope of a #DEFINE macro is the translation unit. That is the current .c or .cpp file that is currently being compiled.

In you code PIN_NUMBER is defined in test.ino. The #include macro literaly copies the content of testLibrary.h into test.ino. So for the compiler this is working perfectly fine as PIN_NUMBER is defined.

Your testLibrary.cpp however is not happy with that. Including testLibrary.h for compilation lacks the definition of PIN_NUMBER.

The Arduino IDE is very limited and does not offer you a way to define PIN_NUMBER globally. This is usually done with the compiler argument -DPIN_NUMBER=3. All translation units will get this argument and thus the compilation would succeed. No need to define PIN_NUMBER in code.

Kwasmich
  • 1,513
  • 12
  • 18
  • Unfortunately adding a compiler argument is not a solution - the whole problem setting was due to attempting to make a standard library which any Arduino IDE user could simply download and include without having to make any subsequent changes. – Zanshin Feb 10 '21 at 07:35
  • In the answer to a similar question it’s suggested to put the #define in a header file that is then included into all the translation units (i.e., ino, c or cpp files) https://arduino.stackexchange.com/questions/23681/visibility-of-define-between-sketch-and-library – RowanP Mar 06 '22 at 13:49