Writing values to global array inside library function

This is maybe quite high fly but let´s give it a shot.

I have written a library that calculates moving average. It is working fine when I define an array insid the library, to which the averaged values are added.

Problem is that I have a low power project and I use RTC memory of ESP8266 to keep data while device is sleeping. If I use my library, the array inside the library will be empty each time the device wakes up.

The question: Can I define to which array I want to write values inside my library functions?

I have found a working solution, but if works only with a function, not with the library:

int muisti[10];

void setup() {
  Serial.begin(9600);
  Serial.println("alkaa");
 

}

void loop() {

  for(byte x = 0; x < 10; x++){
    muisti[x] = 5;
    Serial.print(muisti[x] + (String)" ");
  }
  Serial.println(" ");

  funktio(muisti, 10);

  delay(1000);
 
}

void funktio(int *arska, int size){
  
  Serial.println("Funktiossa");

  for(byte x = 0; x < 10; x++){
    arska[x] = 3;
    Serial.print(muisti[x] + (String)" ");
  }
  Serial.println(" ");
  
}

The above code works like I want. It first puts 5 to every array member in muisti[10]. Then in function "funktio" it points to the array and writes 3 to every member of muisti[10]:

alkaa
5 5 5 5 5 5 5 5 5 5  
Funktiossa
3 3 3 3 3 3 3 3 3 3  
5 5 5 5 5 5 5 5 5 5  
Funktiossa
3 3 3 3 3 3 3 3 3 3

How should I implement this if i want to define the address of the array in my library?

If my library is <movingAverage.h> and I have the following functions in it:

public:
    movingAverage(int *avgArray, int userAvgSize);
	void writeValue(float newValue);
	void writeValueBetween(int valueNr, float value);
	void writeAllValues(float value);
	float getValueBetween(int valueNr);
	float getAverage();

I start the library with

movingAverage movAve(muisti, 10);

In this command I would "write down" the address of "muisti[10]" so that when calling:

movAve.writeValue(4.0);

4.0 would be written to muisti[0] and not to an array inside the library?

An example code:

#include <movingAverage.h>

float muisti[10];

movingAverage testi(muisti, 10);

void setup() {
  Serial.begin(9600);
  Serial.println("alkaa");

  testi.writeAllValues(5.0);  //write all muisti[] members to 5.0

  for(byte x = 0; x < 10; x++){
    Serial.print(muisti[x] + (String)" ");  //print muisti[]. Should print 5 5 5 5 5 5 5 5 5 5 5
  }
  Serial.println(" "); 

  
}

void loop() {
  

}

The only thing I get is errors

The sketch is converted to a cpp file, and compiled. The library is a cpp and header file. It is compiled separately.

If you want to declare an array in the sketch, and read from/write to it in the library, you tell the library that the array exists, by repeating the declaration, with the extern keyword, so the linker knows that there is not a separate array of the same name.

If you want to declare the array in the library, then you tell the sketch that the array exists, by repeating the declaration, with the extern keyword, so the linker knows that there is not a separate array of the same name.

Keep in mind, though, that doing what you are trying to do complete defeats the concept of encapsulation. The sketch shouldn't know/care how the library persists data. The library should provide a way to accept data and to return data, and those are the ONLY ways that the sketch should be able to get data that the class owns.

If I understood your point correctly, that is not what I want to do.

I do not want to declare an array inside the library. I want the library to write and read values directly to my array outside the library.

Or do you mean that one solution would be to have a separate array int he library and then every time the ESP wakes up I fill the library array with the values from RTC memory array? And before sleeping, asking the updated values from the library and copying them to RTC memory array?

I want the library to write and read values directly to my array outside the library.

So, you tell the library that the array exists, somewhere else, by using

extern someType someArray[someSize];

in the source file. Of course, you need to know what the type is, what the name is, and what the size is.

That is one way to do it. But it is very clumsy and the point with multiple instance library disappears.

I might have 3 instances of the library and each write to different arrays.

But it is very clumsy

It is not. But, that's why I told you that you should not do it.

I might have 3 instances of the library and each write to different arrays.

That was NOT in your original problem statement.

If each instance can deal with a different array, you should provide a method to tell the instance where to store it's data.

Almost certainly, that place should NOT be a global array that any code can manipulate.

PaulS:
It is not. But, that's why I told you that you should not do it.
That was NOT in your original problem statement.

If each instance can deal with a different array, you should provide a method to tell the instance where to store it's data.

Sorry for not being clear. I thought that it was more or less obvious. When wanting to do only one thing, a function would have been sufficient. I made it a library so that it can be used as flexibly as possible.

The question I am asking for is this method because I do not know it.

NusNus:
Sorry for not being clear. I thought that it was more or less obvious. When wanting to do only one thing, a function would have been sufficient. I made it a library so that it can be used as flexibly as possible.

The question I am asking for is this method because I do not know it.

Then give your library a pointer to the array (plus its size) and have it perform its operations on that pointer.

Jiggy-Ninja:
Then give your library a pointer to the array (plus its size) and have it perform its operations on that pointer.

I have and am trying this but get errors.

I get error message:

In member function 'void movingAverage::writeAllValues(float)':
error: invalid types 'float[int]' for array subscript

     arrayAddress[x] = value;

Arduino code:

#include <movingAverage.h>

float muisti[10];

movingAverage testi(muisti, 10);


void setup() {
  Serial.begin(9600);
  Serial.println("alkaa");

  testi.writeAllValues(5.0);

  for(byte x = 0; x < 10; x++){
    Serial.print(muisti[x] + (String)" ");
  }
  Serial.println(" "); 

  
}

void loop() {
  

}

Library .cpp:

#include "Arduino.h"
#include "movingAverage.h"

movingAverage::movingAverage(float *avgArray, int userAvgSize){
 if(_userAvgSize > _avgSize){_userAvgSize = _avgSize;}
 else _userAvgSize = userAvgSize; 
 
 arrayAddress = *avgArray;
}

void movingAverage::writeAllValues(float value){
 for(int x = 0; x < _avgSize; x++){
    arrayAddress[x] = value;
  }
}

(some irrelevant functions are left out from here)

Library .h:

#ifndef movingAverage_h
#define movingAverage_h

#include "Arduino.h"

class movingAverage
{
  public:
    movingAverage(float *avgArray, int userAvgSize);
	void writeValue(float newValue);
	void writeValueBetween(int valueNr, float value);
	void writeAllValues(float value);
	float getValueBetween(int valueNr);
	float getAverage();
	
  private:
	int _userAvgSize = 0;
	const int _avgSize = 10;
	float _avgArray[10];
	float arrayAddress;

};

#endif

Any ideas why the compiler error?

Any ideas why the compiler error?

The compiler error is reported because your syntax is wrong.

You pass a pointer to the function. You should store that pointer in a pointer variable.
In the private section of the class:

float *ptrArray;

In the constructor:

movingAverage::movingAverage(float *avgArray, int userAvgSize)
{ // Down here where it belongs
   ptrArray = avgArray;

When initializing the array:

void movingAverage::writeAllValues(float value)
{
   for(int x = 0; x < _avgSize; x++)
   {
      ptrArray[x] = value;
   }
}

Thank you PaulS and Jiggy-Ninja!! Now it is working!! I gave you both karma.

I can now have many instances and the new calculated values goes to arrays outside the library.

This library makes my life so much easier. Maybe I could tell something about the project.

I have a weather station with ESP8266. I have connected an ADS1115 I2C-AD board to get temperature (NTC), light (LDR), battery voltage and the esp VCC ~3,3V (to get calculation results as good as possible. ADS1115 has its own reference voltage source so it is possible to measure the 3,3V that board and perhiperals use).

  • The station is in deep sleep for 1 minute
  • wakes up and takes the 4 readings, calculates temperature in C and converts voltage values to volts and in future light to lux, once I get a better measurement than LDR.
  • Then it sleeps again for 1 minute.
  • After 10 minutes of cycles, it connects to wifi and sends the values to Thingspeak. Then cycle starts again.

The reason to calculate moving average is because I do measurements 10 times before sending. So I calculate the average and sen it to the cloud.

But thanks again! You saved my day :slight_smile:

Here is the Thingspeak channel: https://thingspeak.com/channels/618120[/]

It is in very early testing stage so the values can be anything.

The reason to calculate moving average is because I do measurements 10 times before sending. So I calculate the average and sen it to the cloud.

This does NOT explain why the arrays to save the data in are global. Each instance of your class should own it's own data, which should be private. Each instance should have a method to return the moving average. The sketch should NOT have access to the array(s).

PaulS:
This does NOT explain why the arrays to save the data in are global. Each instance of your class should own it's own data, which should be private. Each instance should have a method to return the moving average. The sketch should NOT have access to the array(s).

The reason lies in the sleeping of the MCU. When the processor goes to deep sleep, ram looses data and the moving average array would also get destroyed.

For this reason the library needs to write directly to an array in a struct, which is copied to RTC memory before sleep. This memory does not get cleared in sleep mode.

Out of curiosity, how woul you Paul have tackled the problem with sleeping processor and loss of ram?

For this reason the library needs to write directly to an array in a struct, which is copied to RTC memory before sleep. This memory does not get cleared in sleep mode.

Why can't the library handle writing the data to the RTC memory?

Or, why can't the instance have a method that returns the number of elements in the array, and another that returns the nth element of the array?

Out of curiosity, how woul you Paul have tackled the problem with sleeping processor and loss of ram?

Using a private array and either of the above two options.

Having the instance store its own data has the advantage in that the sketch needs to know nothing about how the instance accomplishes the task. But, it has the disadvantage in that the sketch doesn't know anything about where the instance is storing the data, so the sketch can't make sure that one instance doesn't overwrite data from another instance.

This can be resolved by having the sketch tell the instance where to store the data (what address to start at), and having the instance return the number of addresses it used.

PaulS:
Why can't the library handle writing the data to the RTC memory?

I find it much clearer that the RTC memory is written from one place just before the mcu goes to sleep. Also the library would be unusable with Arduino because it does not have RTC memory.

PaulS:
Or, why can't the instance have a method that returns the number of elements in the array, and another that returns the nth element of the array?
Using a private array and either of the above two options.

I have a function for this in the library. I thought this to be inconvinient because at wake up the array members needs to be copied to the private array and before sleep writing them back to RTC memory struct and then to RTC memory.

PaulS:
Having the instance store its own data has the advantage in that the sketch needs to know nothing about how the instance accomplishes the task. But, it has the disadvantage in that the sketch doesn't know anything about where the instance is storing the data, so the sketch can't make sure that one instance doesn't overwrite data from another instance.

This can be resolved by having the sketch tell the instance where to store the data (what address to start at), and having the instance return the number of addresses it used.

I agree that this would be a very good approach. My original plan was to use a private array.