How to dynamically change which #define is used

I'm using a special library (P1AM_Serial.h) that uses the terminology Port1 in place of Serial1. I need to make this library compatible with both the SAMD21 that is using the Port1, and the atmega2560 that uses Serial1. So normally I'd do something like this:

#define MEGA2560
//#define SAMD21

#ifdef MEGA2560
#define cereal (Serial1)
#endif

#ifdef SAMD21
#include <P1AM_Serial.h>
#define cereal (Port1)

#endif

This enables me to define which board architecture I'm using, that way in my code I can use the singular cereal to mean either Port1 or Serial1.

The problem is in order to change which architecture I'm using, I have to change the #defines in my library. This updates the library and will no longer simultaneously work for my SAMD21 board and my 2560 board. I also don't want to make separate files/libraries, because all the functions are shared across boards, and I'm in the process of developing the library. I would have to continually copy/paste to separate files......I know there's a way around this.

How?

I need to be able to create an test object and pass as an argument which architecture I'm using, and have cereal assigned accordingly. I tried doing a simple if/else in my constructor, but of course #define is pre-processor, therefore the value is set before I ever even create an object.

.ino

#include "test.h"

test obj;

void setup()

{

obj.function();

}

void loop()

{

}

.h

#pragma once
#include <Arduino.h>

class test
{
  public:
    test();
    void function();


};

.cpp

#include "test.h"

test::test()
{

}

void test::function()
{
  
}

Can you make use of the defined at build time board definitions that are automatically created and selected base on what board you're compiling for?

#ifdef ARDUINO_AVR_MEGA2560
#define cereal (Serial1)
#endif

#ifdef ARDUINO_SAMD_ZERO
#include <P1AM_Serial.h>
#define cereal (Port1)

#endif

It might be ARDUINO_SAMD_MKR1000, ARDUINO_SAMD_NANO_33_IOT, ARDUINO_SAMD_MKR1000, etc., etc., depending on which particular SAMD board you're building for.

Implement a HAL (Hardware Abstraction Layer) and keep the Port1/Serial1 object in a dedicated reference. Don't insist in initialization at compile time, leave it to library startup time.

Why? That doesn't make sense. If you compile for a special board it will in any case not run on another. As @van_der_decken already pointed out, there are predefined values that can be asked with #ifdef to distinguish between the boards at compiletime. Theses defines are -d options of the compiler when it is called in the build process. If you select 'Show verbose output during compilation' in preferences you can see these -d options that set the board specific defines.

I see the problem in the use of different libraries, depending on the current board. These different libraries offer different access ports, which have to be properly selected in user libraries and code. I'd add a .begin() method to the user library where the right "cereal" can be given to the library.

imho it makes sense to hand over a reference to a stream object in the constructor and use that reference instead of a hardcoded Port1/Serial1 (even if set by a define makro).

(see also answer #3).

I absolutely can! Thank you very much for the easy solution.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.