single code for multiple libraries

Hello,

I just got a w5500 based enet shield which seems to be working fine and I’d love to have one code for both 5100 and 5500 using the magic #if compiler directive but I don’t know how to do it

for 5100 I need to
#include <Ethernet.h>
#include <ICMPPing.h> //version for 5100

and ‘my’ libraries folder, must have the dirs

icmp_ping (icmp 5100 things)
ds3234 (RTC things)
guy_lib (my things)
ThingSpeak (cloud things)

for 5500 I need to
#include <Ethernet2.h>
#include <ICMPPing.h> //version for 5500 (same name!)

and my libraries folder must have the dirs

Ethernet2
Arduino-Ping-W5500-master
ds3234
guy_lib
ThingSpeak

So back to my question: What is the ‘correct’ or ‘elegant’ or ‘professional’ way to have one code accommodating both hw cards?

Thanks

Interesting question that - hopefully someone will come along with the answer .
I did wonder if there is something that can be read from the ethernet card to identify it , and wether you can have “#include” selected within code as a way of doing this.

Following this ...

hammy:
Interesting question that - hopefully someone will come along with the answer .
I did wonder if there is something that can be read from the ethernet card to identify it , and wether you can have “#include” selected within code as a way of doing this.

Following this ...

Reading from the card is design time. #if and #include are compile time. So this plan won't work.

If you want to be able to use both, two options.

  1. Know at design and have an #ifdef statement at the very top (line #1) that you can comment out or allow in that will switch between the two options.
  2. Include two sets of code, with if statements based on having read "something" from the board to identify it.

I have attempted to do #2 for the three different RTC chips available on the SD/RTC datalogging shields that are available. Unfortunately, there is nothing to read from the chip to identify it to the processor. I ended up sacrificing two input pins and solder a jumper or two in place to ID the boards through digital inputs during setup.

guy_c:
for 5500 I need to
#include <Ethernet2.h>

Why is that? Are you aware that the latest 2.0.0 release of the official Ethernet library supports W5100, W5200, and W5500, with automatic detection of which chip is in use? The only valid reason for still using the outdated Ethernet2 library is that the new Ethernet library does use more memory. But there are other significant improvements that make the new Ethernet library much superior to Ethernet2.

guy_c:
#include <ICMPPing.h> //version for 5500 (same name!)

If there really is a different ICMPPing library for W5100 vs W5500 then that will not be possible to select automatically. As adwsystems mentioned, it is possible to determine which chip is used at run time. In fact there is a function in the new Ethernet library that makes this super easy:
https://www.arduino.cc/en/Reference/EthernetHardwareStatus
But you can not control #include directives based on run time data. It must be known at compile time and there is no way to automatically detect which Ethernet controller chip is being used at compile time.

You can do something like this:

#define USING_W5100  //comment this line when W5500 is in use
#ifdef USING_W5100 
#include <ICMPPing-W5100.h>
#else
#include <ICMPPing-W5500.h>
#endif
#include <ICMPPing.h>

but you will need to manually comment/uncomment that first line according to which Ethernet controller you’re using. You’ll notice the #include directives for ICMPPing-W5100.h vs. ICMPPing-W5500.h. If you have two libraries that have the same file name, for example:

{sketchbook folder}
|_libraries
|_Arduino-Ping-W5100-master
| |_ICMPPing.h
|_Arduino-Ping-W5500-master
|_ICMPPing.h

Then which one the Arduino IDE decides for #include <ICMPPing.h> to use is somewhat random, and can’t be controlled well.

But the Arduino IDE will give preference to the library that contains a file which has been used in a previous #include directive. So if you add a dummy empty .h file to each library:

{sketchbook folder}
|_libraries
|_Arduino-Ping-W5100-master
| |_ICMPPing.h
| |_ICMPPing-W5100.h
|_Arduino-Ping-W5500-master
|_ICMPPing.h
|_ICMPPing-W5500.h

and then add an #include directive for the dummy filename before the ambiguous filename, then you can control which of the libraries will be used.

A better solution would be for the ICMPPing library to be written so that it’s compatible with both Ethernet controller chips, but I’m not sure how difficult that would be or whether it would introduce overhead.

Thanks pert for your detailed answer

now I have two more questions

  1. Can you please tell how do I replace my current Ethernet 1.1.2 in arduino/libraries by the 2.0.0? Do I simply download from gitHub, unzip and replace?

  2. the new icmp (5500) has in its ICMPPing.h an #include Ethernet2.h so I guess that I must include it in the #if of my code right?

Thanks again

guy_c:

  1. Can you please tell how do I replace my current Ethernet 1.1.2 in arduino/libraries by the 2.0.0? Do I simply download from gitHub, unzip and replace?
  • Sketch > Include Library > Manage Libraries
  • Wait for the download to finish
  • In the "Filter your search..." box, type "ethernet"
  • Click on "Ethernet by Various"
  • Click "Update"
  • Wait for update to finish
  • Click "OK"

A summary of the changes between 1.1.2 and 2.0.0 can be found here:
https://www.pjrc.com/arduino-ethernet-library-2-0-0/

guy_c:
2) the new icmp (5500) has in its ICMPPing.h an #include Ethernet2.h so I guess that I must include it in the #if of my code right?

Well, you wouldn't want to use the Ethernet library in your sketch and the Ethernet2 library in the ICMPPing library. That will probably result in an error. However, since the Ethernet2 and Ethernet libraries have a compatible API, it's likely the only difference between your W5100 ICMPPing library and your W5500 ICMPPing libraries is which Ethernet library they use. So, once you update to Ethernet library version 2.0.0, try using the W5100 ICMPPing library with the W5500.

If you look at the command line implementation of the compiler you will see a switch similar to -mmcu=atmega328p. This tells the compiler which board/processor to build for. In a similar manner you could have a switch that tells the compiler which enet shield you're using. The compiler cannot query the processor any more than it can query the shield. This is called cross-compiling as you are not in fact compiling the code on the destination platform. The bottom line is that the compiler needs to know what hardware you have. You mimic this operation in your code by #define 'ing some identifier unique to each board, all but one being commented out for compilation. The balance of your code is simply then enclosed in #ifdef/#endif pre-processing directives to include or exclude the bits you want/don't want.

In either case, the definition is made before you compile so whether you do it at the command line or first thing in your code is somewhat irrelevant.