Common namespace in multiple translation units

Sorry guys, this was left out due to my haste and was added here later...
Hello everyone!
The procedural spaghetti code's complexity has reached my threshold. With little time and even less experience, I "moved the critical parts onto the OOP plate."
With the brilliant manageability of OOP came the issue of communication between the "OOP plates," i.e., the instances of individual (custom and 3rd-party) classes.
Unfortunately, even after a week of gathering information (forums, tutorials), I couldn't solve the problem...

The project:
A serial display is divided into 7 parts, of which 6 are equal. I made 2 classes to write the values on the display. The display has a factory library (class with public methods), at start must make 1 object.
There are buttons on the display, which are also treated by the display class (other) method.
I made two classes (in stand-alone .cpp/.h files), and I would like to use the (factory) methods of display.
Naturally (due to different translation units), my own class instances cannot see the methods of a class instantiated in another file.
I tried to use a namespace, but every attempt ends with the namespace created in one file not being visible in other files.
allDisplays.h

// display factory class
#include <genieArduino.h>
Genie uLCD90DCT;
// my classes
#include "InvDisplay.h"
InvDisplay* invDisplays = new InvDisplay[6];
#include "smallDisplay.h"
smallDisplay display;

allDisplays.ino

#include "allDisplays.h"
void setup() {
Serial1.begin(9600);
  uLCD90DCT.Begin(Serial1);
  uLCD90DCT.AttachEventHandler(displayEventHandler);  // Attach the user function Event Handler for processing events
.
.
}
void displayEventHandler() {
  genieFrame Event;
  uLCD90DCT.DequeueEvent(&Event);
.
.
}
void loop() {
  uLCD90DCT.DoEvents();  // This calls the library each loop to process the queued responses from the display
}

my classes
smallDisplay.h

#ifndef smallDisplay_h
#define smallDisplay_h

#include <Arduino.h>
#include <String.h>
class smallDisplay {
public:
  smallDisplay();
.
.
private:
void _setGENIE_OBJ_LED_DIGITS(uint8_t _LeddigitsID, uint16_t value);
.
};
#endif

smallDisplay.cpp

#include "smallDisplay.h"

smallDisplay::smallDisplay() {
}
.
.
void smallDisplay::_setGENIE_OBJ_LED_DIGITS(uint8_t _LeddigitsID, uint16_t value) {
  uLCD90DCT.WriteObject(GENIE_OBJ_LED_DIGITS, _LeddigitsID, value);
} // without any namespace, (of course) this error message: Compilation error: 'uLCD90DCT' was not declared in this scope

The other class works almost the same way (but with 6 instances). For the sake of clarity, I didn't copy the entire code; I omitted the non-relevant parts.

I tried to use a namespace,

// in allDisplays.h
.
namespace nsGenie{
Genie uLCD90DCT;
}
.
// smallDisplay.cpp
.
void smallDisplay::_setGENIE_OBJ_LED_DIGITS(uint8_t _LeddigitsID, uint16_t value) {
  nsGenie::uLCD90DCT.WriteObject(GENIE_OBJ_LED_DIGITS, _LeddigitsID, value);
}
.

but the error message is always this: Compilation error: 'uLCD90DCT' was not declared in this scope

Ok., let it be:
allDisplays.h

// display factory class
#include <genieArduino.h>
Genie uLCD90DCT;
// my classes
#include "InvDisplay.h"
InvDisplay* invDisplays = new InvDisplay[6];
#include "smallDisplay.h"
smallDisplay display;

allDisplays.ino

#include "allDisplays.h"
void setup() {
  Serial1.begin(9600);
  uLCD90DCT.Begin(Serial1);
  uLCD90DCT.AttachEventHandler(displayEventHandler);  // Attach the user function Event Handler for processing events
  for (uint8_t i = 0; i < 6; i++) {
    invDisplays[i].init(i);
  }
}
void displayEventHandler() {
  genieFrame Event;
  uLCD90DCT.DequeueEvent(&Event);
  // later do something, if a button is pressed
}
void loop() {
  uLCD90DCT.DoEvents();  // This calls the library each loop to process the queued responses from the display
}

my classes
smallDisplay.h

#ifndef smallDisplay_h
#define smallDisplay_h

#include <Arduino.h>
#include <String.h>
#include <genieArduino.h>

const uint8_t a1aktI_LeddigitsID = 6;

class smallDisplay {
public:
  smallDisplay();
  void setA1aktI(uint16_t value);
private:
  void _setGENIE_OBJ_LED_DIGITS(uint8_t _LeddigitsID, uint16_t value);
};
#endif

smallDisplay.cpp

#include "smallDisplay.h"

smallDisplay::smallDisplay() {
}

void smallDisplay::setA1aktI(uint16_t value) {
  _setGENIE_OBJ_LED_DIGITS(a1aktI_LeddigitsID, value);
}

void smallDisplay::_setGENIE_OBJ_LED_DIGITS(uint8_t _LeddigitsID, uint16_t value) {
  uLCD90DCT.WriteObject(GENIE_OBJ_LED_DIGITS, _LeddigitsID, value);
}

InvDisplay.h

#ifndef InvDisplay_h
#define InvDisplay_h

#include <Arduino.h>
#include <String.h>
#include <genieArduino.h>
const uint8_t invSetU_LeddigitsID_arr[] = { 2, 8, 9, 10, 11, 12 };

class InvDisplay {
public:
  InvDisplay();
  void init(uint8_t arrIdx);
  void setInvSetU(uint16_t value);

private:
  void _setGENIE_OBJ_LED_DIGITS(uint8_t _LeddigitsID, uint16_t value);
  uint8_t _invSetU_LeddigitsID;
};
#endif

InvDisplay.cpp

#include "InvDisplay.h"

InvDisplay::InvDisplay() {
}

void InvDisplay::init(uint8_t arrIdx) {
  _invSetU_LeddigitsID = invSetU_LeddigitsID_arr[arrIdx];
}

void InvDisplay::setInvSetU(uint16_t value) {
  _setGENIE_OBJ_LED_DIGITS(_invSetU_LeddigitsID, value);
}

void InvDisplay::_setGENIE_OBJ_LED_DIGITS(uint8_t _LeddigitsID, uint16_t value) {
  uLCD90DCT.WriteObject(GENIE_OBJ_LED_DIGITS, _LeddigitsID, value);
}

This is the complete test code.

you could handover a reference to the instance of the display object to your class.
Then your class can call member function of the referenced object.

edit:
short LCD examle with a blinking indicator:

/*
   Reference in a class to another instance
   https://forum.arduino.cc/t/common-namespace-in-multiple-translation-units/1225443/4

   2024-02-21 by noiasca
   source not in thread
   keep as example
*/

#include <LiquidCrystal_I2C.h>     // if you don´t have I2C version of the display, use LiquidCrystal.h library instead

LiquidCrystal_I2C mydisplay(0x27, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display

// another class which takes the reference to an existing object
class Indicator {
  private:
    uint32_t previousMillis;                     // last time shown
    bool active = false;                         // indicator is active
    bool state = false;                          // show/not show character
    const LiquidCrystal_I2C &lcd;                // the other instance
    const uint8_t character;                     // the character to be displayed
    const uint8_t col;                           // on which column
    const uint8_t row;                           // on which row
    const uint16_t interval;                     // blink intervalhow long visible (after that time, the indicator will disapear)
  public:
    Indicator(LiquidCrystal_I2C &lcd, uint8_t character, uint8_t col, uint8_t row, uint16_t interval = 500) :
      lcd(lcd), character(character), col(col), row(row), interval(interval) {}
    
    void on() {
      if (active == false) {
        lcd.setCursor(col, row);
        lcd.write(character);
        previousMillis = millis();
      }
      active = true;
    }
    void off() {
      if (active == true) {
        lcd.setCursor(col, row);
        lcd.write(' ');
      }
      active = false;
    }
    void update() {                              // to be called in loop()
      if (active == true && interval > 0) {
        if (millis() - previousMillis > interval) {
          previousMillis = millis();
          lcd.setCursor(col, row);
          if (state) lcd.write(character); else lcd.write(' ');
          state = !state;
        }
      }
    }
};

Indicator indicatorActivity(mydisplay, '*', 15, 0);

void setup() {
  mydisplay.init();                       // initialize the 16x2 lcd module
  mydisplay.backlight();                  // enable backlight for the LCD module
  indicatorActivity.on();
}

void loop() {
  indicatorActivity.update();
}

Thank you, that's exactly how I solved it, just didn't have time to report it on the forum.

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