Define Structs and instances of structs in a Library

Hi All,

I’ve done some research and found an old topic that got me quite close to my goal. The goal is this:

I want to create a library containing structs and assign my global variables to them within the Library. I would like to include this library into sketches that need to use these variables.

I do NOT need/ nor do i want to create the instances of these structs outside of the library (AKA, I don’t want to have to create the instances in my sketches; i would rather complete all of instances for multiple structs within the library, then call them.

How do I do such a thing?

// UIVariables4.h

#ifndef UIVariables4_h
#define UIVariables4_h

#include "Arduino.h" //needed to include standard arduino library

struct Test
{
Test(); //defines default constructor; gets called when the instance is created and initializes the struct variables to the defualts
unsigned int looptime;
unsigned int ui;
unsigned int sensor;
unsigned int tolerance;
};

#endif
//UIVariables4.cpp

#include "Arduino.h"
#include "UIVariables4.h"

Test::Test(){
looptime = 1000;
ui = 500;
sensor = 2;
tolerance = 25;
}
#include <Comparator.h>
#include <UIVariables4.h> //Library containing global UI variables
//Test A; //Used for creating instance outside of library

unsigned int i = 0; //iteration counter
byte digitalOutput;
void setup() {
  Serial.begin(9600);
}

void loop() { //Loop is to test function
  while (i < Test.A.looptime) {
    int UI = Test.A.ui + i;
    int Sensor = Test.A.sensor * i;
    digitalOutput = comparator(Sensor, UI, Test.A.tolerance);
    Serial.println(digitalOutput);
    i++;
  }
}

The issue with the attaches is I must define the instance out the class in my sketch, then use “A.looptime” and so on.

I have SEVERAL structures I want to integrate a library, but I’m struggling with getting the first 1 working properly.

Any guidance would be greatly appreciated, and an explanation “why” doing something different will work would be even better!

It sounds more like you should be using classes instead of structs.

A struct is like a special case of a class. The struct only contains variables. A class can contain variables and the functions which operate on those variables. Some variables can be private, meaning that nobody else can mess with them without going through the defined functions. Some variables can be public to allow easy access to them.

I think that the comparator() function should be a method inside the class. (In classes, we call the functions methods. I don't know why. I think it comes from Java or another object-oriented language.) Then you don't need to pass it all the stuff every time. It already knows what the tolerance is.

The code might look like this:

void loop() {
  byte digitalOutput;
  if(A.timeToTakeSample()) {
    A.takeSample();
    digitalOutput = A.comparator();
    Serial.println(digitalOutput);
  }
}

Of course there's a lot of other things you could do. You could wrap all of this into one public method and make the timeToTakeSample() a private method.

Once you've defined the Test class in your library, you will want to use several of them in the actual Arduino program. A, B, C or whatever. So you always define the class in the library and then the actual instances are created by the Arduino sketch. While it is legal for the .h file to create the instances, that's a bad idea because it always creates them, every time you include the library. You can't predict now what you are going to use this for in the future. Instead of A,B,C, you should be using names like refrigeratorTemperature and rollPositionDegrees which make sense to the final sketch.

Not sure what you’re going for here, but yes, you can create instances as part of the library. Some of the standard libraries you’re familiar with do so: WiFi, Serial, Wire, SPI, etc. I don’t have an opinion on whether that’s the right thing to do for your application. But, one way is shown below. I cut out the Comparator.h stuff since I don’t have that library and it’s not germane to your question.

.h File:

// UIVariables4.h
#ifndef UIVariables4_h
#define UIVariables4_h

#include "Arduino.h" //needed to include standard arduino library

struct Test
{
  Test(); //defines default constructor; gets called when the instance is created and initializes the struct variables to the defualts
  static const int numInstances = 4;
  unsigned int looptime;
  unsigned int ui;
  unsigned int sensor;
  unsigned int tolerance;
};

extern Test myInstances[];
#endif

.cpp File:

//UIVariables4.cpp

#include "Arduino.h"
#include "UIVariables4.h"

Test::Test(){
looptime = 1000;
ui = 500;
sensor = 2;
tolerance = 25;
}

Test myInstances[Test::numInstances];

.ino File:

#include "UIVariables4.h" //Library containing global UI variables

unsigned int i = 0; //iteration counter
byte digitalOutput;
void setup() {
  Serial.begin(115200);
  for (int i = 0; i < Test::numInstances; i++) {
    Serial.println(myInstances[i].sensor);
  }
}

void loop() { }

I appreciate the time you folks take to reply, it’s EXTREMELY difficult to figure out how to perform these kinds of tasks without spending significant amounts of time understanding different approaches.

I believe the responses you both provided are useful and they may be feasible to achieve my end goal. I think I gave you a somewhat bad explanation/example of what I want.

Take the following sketch, for example:

struct input {
  byte ON;
  byte Hold;
} Polarity, State, Pin;

//Polarity is a user defined input(UI), so include that in UIlibrary
//State is not a predefined user input, want State.XXXX to be variable saved in separate location
//Pin is a user defined input(UI), so include that in UIlibrary

struct Event {
  float Time;
} Start, End;
//Event Start and End are user defined inputs(UI), so include that in UIlibrary

void setup() {
  Serial.begin(9600);

  //***** UI Polarity Initialization ***** Save in UILibrary *****//
  Polarity.ON = 1; //0 = LOW activation; 1 = HIGH activation
  Polarity.Hold = 1; //0 = LOW activation; 1 = HIGH activation


  //***** UI Pin Initialization ***** Save in UILibrary *****//
  Pin.ON = 7;
  Pin.Hold = 6;

  pinMode(Pin.ON, INPUT);
  pinMode(Pin.Hold, INPUT);


  //***** UI Event Times Initialization*****Save in UILibrary*****//
  Start.Time = 0.250; //Time when Correction outputs begin
  End.Time = 2.000; //Time when Correction outputs begin

}

void loop() {

  State.ON = digitalRead(Pin.ON); //Update input switch state
  State.Hold = digitalRead(Pin.Hold); //Update input switch state

  if ( State.Hold == Polarity.Hold && State.ON == Polarity.ON) {
    Serial.print("Loop 1 Time:  ");
    Serial.println(millis());
  }

  else if (State.Hold != Polarity.Hold && State.ON == Polarity.ON) {
    Serial.print("Loop 2 Time:  ");
    Serial.println(millis());
    if (millis() >= (Start.Time * 1000) && millis() <= (End.Time * 1000)) {
      Serial.print("Loop 3 Time:  ");
      Serial.println(millis());
    }
  }
}

I’d like to save the UI variables in their own Library( i.e. UILibrary), and include it in other sketches so that I do not have to copy and past these things over and over again (Seems silly, but there are many more variables than this in the project).

Is it more clear what I desire now?

Can I use “Classes” as cleanly as I use “structs” here?

The struct only contains variables.

A structure can contain a function.

MorganS:
It sounds more like you should be using classes instead of structs.

A struct is like a special case of a class. The struct only contains variables. A class can contain variables and the functions which operate on those variables. Some variables can be private, meaning that nobody else can mess with them without going through the defined functions. Some variables can be public to allow easy access to them.

no, not so

larryd:
A structure can contain a function.

exactly.

the ONLY difference between a struct and a class is that in a class, members are private by default versus a struct where they are public by default.

plimptj:
Is it more clear what I desire now?

Sadly, no. It's still not clear to me what code constitutes your library. Regardless, the method I posted in Reply #2 stands as my recommendation. Others may prefer a different technique.

I think that what you're looking for is something like the below.

mydata.cpp

#include "mydata.h"

// define the array of structs
struct MYDATA myData[] =
{
  {2, 3},
  {4, 5},
};

mydata.h

#ifndef MYDATA_H
#define MYDATA_H

struct MYDATA
{
  int x;
  int y;
};

// tell the compiler about the existence of the myData array for any file that includes mydata.h
extern struct MYDATA myData[];
#endif

And the sketch

#include "mydata.h"

void setup()
{
  Serial.begin(115200);
  Serial.println(myData[0].x);
  Serial.println(myData[0].y);
}

void loop()
{
  // put your main code here, to run repeatedly:

}