C++ Confusion - Global Usage

I’m sure my question will seem nonsensical to some but i have been struggling for a couple of days and will really appreciate the support. Long time C programmer but never moved in C++.

I am doing some CEC stuff using the Arduino CEClient library. All completely fine and working well in a simple test file with all functions in a main.ino file. For ease this is the example code provided with the library:


#include "CEClient.h"

#define CEC_PHYSICAL_ADDRESS    0x1000
#define CEC_INPUT_PIN           2
#define CEC_OUTPUT_PIN          3

// create a CEC client
CEClient ceclient(CEC_PHYSICAL_ADDRESS, CEC_INPUT_PIN, CEC_OUTPUT_PIN);


void setup() {

    Serial.begin(115200);

    // initialize the client with the default device type (PLAYBACK)
    ceclient.begin();

    // enable promiscuous mode (print all the incoming messages)
    ceclient.setPromiscuous(true);

    // enable monitor mode (do not transmit)
    ceclient.setMonitorMode(true);
}

void loop() {

    // run the client
    ceclient.run();
}

//CEClient.h

class CEClient : public CEC_Device {

typedef void (*OnReceiveCallbackFunction)(int, int, unsigned char*, int);
typedef void (*OnTransmitCompleteCallbackFunction)(bool);

public:
    CEClient(int physicalAddress, int inputPin, int outputPin=-1);
    void begin(CEC_DEVICE_TYPE type = CEC_LogicalDevice::CDT_PLAYBACK_DEVICE);
    bool isReady();
    bool write(int targetAddress, unsigned char* buffer, int count);
    int getLogicalAddress();
    void setPromiscuous(bool promiscuous);
    void setMonitorMode(bool monitorMode);
    void onTransmitCompleteCallback(OnTransmitCompleteCallbackFunction);
    void onReceiveCallback(OnReceiveCallbackFunction);
    void run();

private:
    void OnTransmitComplete(bool);
    void OnReceive(int source, int dest, unsigned char* buffer, int count);
    void OnReady();
    OnTransmitCompleteCallbackFunction _onTransmitCompleteCallback;
    OnReceiveCallbackFunction _onReceiveCallback;
    bool _ready;
};

I am now looking to integrate this code into a much larger project, normally no more than a bit of copy paste but this project is structured into a number of separate files to keep this organised.

My problem quite simply is that I can’t access the ceclient functions from my other files without getting “not available in this scope” type errors. Other functions are much more useful stuff like ceclient.write etc.

If this was C I would solve the issue in moments (global variable in the ino, external in the header of the other file) but my total lack of OO programming has caught me out here. I can’t even find the right terms to search to try and help me solve what I am sure is a trivially simple issue.

Here is what I learned, it is on the forum I THINK under tutorials I THINK.

Organization.ino

#include "HelperFunctions.h"

void setup() {
  myStruct *ptr;
  initStuff();
  for (uint8_t i = 0; i < numElements; i++) {
    globalArray[i].var2[0] = i + 0.0;
    globalArray[i].var2[1] = i + 4.0;
    globalArray[i].var2[2] = i + 8.0;
    globalArray[i].var2[3] = i + 16.0;
  }

  for (uint16_t i = 0; i < numElements; i++) {
    ptr = doStuff(i);
    ptr->var2[2] += 32.0;
  }
}

void loop() {
}

HelperFuncs.cpp

#include "HelperFunctions.h"

#define SIZE 10
myStruct globalArray[SIZE];          // Global variable
const uint16_t numElements = SIZE;   // Global variable
static myStruct privateArray[SIZE];  // File-level variable

void initStuff(void);                     // Global function
myStruct *doStuff(uint16_t);              // Global function
static void privateFunction(myStruct *);  // File-level function

void initStuff(void) {
  for (uint8_t i = 0; i < SIZE; i++) {
    privateArray[i].var1 = i;
    globalArray[i].var1 = i;
  }
}

myStruct *doStuff(uint16_t dog) {
  privateFunction(privateArray + dog);
  return privateArray + dog;
}

static void privateFunction(myStruct *aPointer) {
  aPointer->var1++;
}

HelperFuncs.h

#ifndef HELPER_FUNCTIONS_h
#define HELPER_FUNCTIONS_h
#include <Arduino.h>

typedef struct {
  uint8_t var1;
  float var2[4];
} myStruct;

extern myStruct globalArray[];      // Global variable
const extern uint16_t numElements;  // Global variable

extern void initStuff(void);         // Global function
extern myStruct *doStuff(uint16_t);  // Global function

#endif

@ceenhad
It is not clear from your question, where did this file CEClient.h come from and where is the implementation of all these functions, the headers of which we see in this file

It’s this library

My issue is not with the library as such, just how to properly declare and reference CEClient across other modules within my own project.

To use the object in other files, include the class header and qualify the object as extern.

# include "CEClient.h"

// Declare the instance (no initializer!)
extern CEClient ceclient;

void someFunction() {
    ceclient.sendMessage(...);  // Use it as needed
}

HTH

a7

Better yet, wrap all that up in a header file:
header.h:

#ifndef HEADER_H
#define HEADER_H

#include <Arduino.h>
#include "CEClient.h"
extern CEClient ceclient;
#endif

Then put #include "header.h" in all the .cpp files and in your main.ino file (and remove #include "CEClient.h" from the main.ino).

Then the ceclient object and all it's class methods will be available in all the .cpp files as well as the main.ino.

From a software design perspective, you should not need to use this library everywhere.
It is best to keep things together that belong together....
One function/module should do one thing...

First of all, install the library in Arduino libraries folder. You don't need to copy the .h file in your project.

Second - to figure out how to use it - see an examples in library repo.

Obviously. But that doesn't mean there'd never be an advantage to separating access to the ceclient object across more than one translation unit.

Agree!

Thanks to those who helped me quickly get this sorted. I was close but just had a bit of a syntax error. No longer pulling my hair out though!