Help requested with circular buffers

Hi, I am new to Arduino programming and am having a problem using circular buffers, I clearly have a mistake in my code somewhere.

I wish to add some debugging to a sketch and want to use a function logit() to insert a record into a circular buffer in the form:-

dd hh:mm

If I call struct.push in the loop() function, the correct record gets inserted into the circular buffer. If I call the logit() function and do the struct.push there, the date/time are correct but not the debug text.
Code:-

#include <CircularBuffer.h>


namespace data {
	typedef struct {
		unsigned int day;
		unsigned int hour;
    unsigned int minute;
    char text[20];
	} record;


	void print(record r) {
		Serial.print(r.day);
		Serial.print(" ");
		Serial.print(r.hour);
		Serial.print(":");
		Serial.print(r.minute);
    Serial.print(" ");
    Serial.println(r.text);
	}
}


CircularBuffer<data::record, 10> structs;
int days=12;
int hours=15;
int minutes=35;
char text[20];
void setup() {
	Serial.begin(9600);
	Serial.println("STARTING UP");
}


void loop() {
		structs.push(data::record{days,hours,minutes,"abcdefg"});
    minutes++;
    structs.push(data::record{days,hours,minutes,"hijk"});
    minutes++;
	  logit(days, hours, minutes, "another test");
    strcpy(text,"morecopiedtext");
    minutes++;
    logit(days, hours, minutes, text);
		Serial.println("Print Stack");
    Serial.print(F("structs size:"));
    Serial.println(structs.size());
		while (!structs.isEmpty()) {
      data::print(structs.shift());
			Serial.println();
		}
		Serial.println("START AGAIN");
    delay(100000);
	
} // end main loop


void logit(int d, int h, int m, char * instr){
  Serial.print("logit = days, hours, minutes, text =");
  Serial.print(d);
  Serial.print(h);
  Serial.print(m);
  Serial.println(instr);
  structs.push(data::record{d,h,m,instr});
}

Outout:-

19:57:57.300 ->STARTING UP
19:57:57.300 → logit = days, hours, minutes, text =121537another test
19:57:57.347 → logit = days, hours, minutes, text =121538morecopiedtext
19:57:57.394 → Print Stack
19:57:57.441 → structs size:4
19:57:57.441 → 12 15:35 abcdefg
19:57:57.441 →
19:57:57.488 → 12 15:36 hijk
19:57:57.488 →
19:57:57.488 → 12 15:37 p
19:57:57.488 →
19:57:57.488 → 12 15:38 ⸮
19:57:57.488 →
19:57:57.488 → START AGAIN

Thanks for any assistance!

Hello,
data::record(d,h,m,instr);
Uses field by field initialisation, this fails for char * to char[20];
char is an array, that is not a simple type.
Best Regards,
Johi.

Thanks a lot Johi. Does anybody have an easy solution to this or do I need to completely rethink my approach?

Welcome

I don't know how your code can compile without errors or at least warnings...

Try:

namespace data
{
  struct record
  {
    unsigned int day;
    unsigned int hour;
    unsigned int minute;
    char text[20];
  };

  void print(record & r)
  {
    Serial.print(r.day);
    Serial.print(" ");
    Serial.print(r.hour);
    Serial.print(":");
    Serial.print(r.minute);
    Serial.print(" ");
    Serial.println(r.text);
  }
}

...

void logit(int d, int h, int m, char * instr)
{
  data::record r;
  r.day = d;
  r.hour = h;
  r.minute = m;
  strcpy(r.text, instr);

  Serial.print("logit = ");
  data::print(r);

  structs.push(r);
}

Thanks for the suggestion Guix, I’ve added my declarations and loop() function to your code but unfortunately it doesn’t compile. As newbie I am afraid I don’t understand the compiler messages :frowning:

Code :-

#include <CircularBuffer.h>


namespace data
{
  struct record
  {
    unsigned int day;
    unsigned int hour;
    unsigned int minute;
    char text[20];
  };


  void print(record & r)
  {
    Serial.print(r.day);
    Serial.print(" ");
    Serial.print(r.hour);
    Serial.print(":");
    Serial.print(r.minute);
    Serial.print(" ");
    Serial.println(r.text);
  }
}


CircularBuffer<data::record, 10> structs;
int days=12;
int hours=15;
int minutes=35;
char text[20];
void setup() {
  Serial.begin(9600);
  Serial.println("STARTING UP");
}




void loop() {
    structs.push(data::record{days,hours,minutes,"abcdefg"});
    minutes++;
    structs.push(data::record{days,hours,minutes,"hijk"});
    minutes++;
    logit(days, hours, minutes, "another test");
    strcpy(text,"morecopiedtext");
    minutes++;
    logit(days, hours, minutes, text);
    Serial.println("Print Stack");
    Serial.print(F("structs size:"));
    Serial.println(structs.size());
    while (!structs.isEmpty()) {
      data::print(structs.shift());
      Serial.println();
    }
    Serial.println("START AGAIN");
    delay(100000);
  
} // end main loop




void logit(int d, int h, int m, char * instr)
{
  data::record r;
  r.day = d;
  r.hour = h;
  r.minute = m;
  strcpy(r.text, instr);


  Serial.print("logit = ");
  data::print(r);


  structs.push(r);
}

Compiler output:-

C:\Users\Jon\Documents\Arduino\guix\guix.ino: In function ‘void loop()’:
guix:49:32: error: cannot bind non-const lvalue reference of type ‘data::record&’ to an rvalue of type ‘data::record’
data::print(structs.shift());

C:\Users\Jon\Documents\Arduino\guix\guix.ino:13:8: note: initializing argument 1 of 'void data::print(data::record&)'
void print(record & r)
^~~~~
exit status 1
cannot bind non-const lvalue reference of type 'data::record&' to an rvalue of type 'data::record'

Here is some code I am using as a ‘circular buffer.’

void fDoTrends( void *pvParameters )
{
  const int magicNumber = 24*2;  << size of buffer
  double    values[2];
  int       lrCount = 0;
  float     lrData = 0.0f;
  float     DataPoints[magicNumber] = {0.0f};
  float     TimeStamps[magicNumber] = {0.0f};
  double    dpMean = 0.0f; //data point mean
  float     tsAtom = 0.0f;
  float     tsUnit = 0.0f;
  float     tsMean = 0.0f;
  for (;;)
  {
    if ( xQueueReceive(xQ_lrData, &lrData, portMAX_DELAY) == pdTRUE )
    {
      if ( lrCount != magicNumber ) <<< here is where the buffer is filled
      {
        DataPoints[lrCount] = lrData;
        TimeStamps[lrCount] = (float)xTaskGetTickCount() / 1000.0f;
        log_i( "lrCount %d TimeStamp %f lrData %f", lrCount, TimeStamps[lrCount], DataPoints[lrCount] );
        lrCount++;
      } else { << once the buffer is filled
        //shift data points collected one place to the left
        for ( int i = 0; i < magicNumber; i++ )
        {
          DataPoints[i] = DataPoints[i + 1];
          TimeStamps[i] = TimeStamps[i + 1];
        }
        //insert new data points and time stamp (ts) at the end of the data arrays
        DataPoints[magicNumber - 1] = lrData;
        TimeStamps[magicNumber - 1] = (float)xTaskGetTickCount() / 1000.0f;
        //calculate data mean, normalize
        for ( int i = 0; i < magicNumber; i++ )
        {
          dpMean += DataPoints[i];
        }
        dpMean /= magicNumber;
        //timestamp mean is ts * (1 / ts_Firstcell - ts_Lastcell[magicNumber]). ts=time stamp
        tsAtom = 1.0f / (TimeStamps[magicNumber - 1] - TimeStamps[0]); // no need to do this part of the calculation every for loop ++
        for (int i = 0; i < magicNumber; i++)
        {
          tsMean = (float)TimeStamps[i] * tsAtom;
          lr.Data( tsMean, DataPoints[i] - dpMean ); // train lr
        }
        lr.Parameters( values );
        //calculate
        tsUnit = TimeStamps[magicNumber - 1] - TimeStamps[magicNumber - 2]; //get the time stamp quantity
        tsUnit += TimeStamps[magicNumber - 1]; //get a future time
        tsUnit *= tsAtom; //setting time units to the same scale
        log_i( "Calculate(x) = %f", lr. Calculate( tsUnit ) ); //calculate next time unit?
        log_i( "Correlation: %f Values: Y=%f and *X + %f ", lr.Correlation(), values[0], values[1] ); // correlation is the strength and direction of the relationship
        lr.Reset();
      }
      //log_i( "DoTheBME280Thing high watermark % d",  uxTaskGetStackHighWaterMark( NULL ) );
    } //if ( xQueueReceive(xQ_lrData, &lrData, portMAX_DELAY) == pdTRUE )
  } //for(;;)
  vTaskDelete ( NULL );
} //void fDoTrends( void *pvParameters )

Ok, change line

void print(record & r)

to

void print(data::record const & r)

If you are new to Arduino it is tempting to use library’s but you will not learn much from them.
Creating a circular buffer is very easy and i made some minor changes to your code without the dependence of using that library and made your code a bit more neat.

namespace data {
struct record{
  unsigned int day;
  unsigned int hour;
  unsigned int minute;
  char text[20];
};
byte structCount = 0;
const byte maxStructs = 10;
data::record structs[maxStructs];
void push(const byte& a_day, const byte& a_hour, const byte& a_minute, const char* a_text);
void printStructs();
}

byte days = 12;
byte hours = 15;
byte minutes = 35;
char text[20];

void setup() {
  Serial.begin(9600);
  Serial.println(F("STARTING UP"));
}

void loop() {
  data::push(days, hours, minutes, "abcdefg");
  minutes++;

  data::push(days, hours, minutes, "hijk");
  minutes++;

  data::push(days, hours, minutes, "another test");
  minutes++;

  Serial.print(F("structs count:")); Serial.println(data::structCount);
  data::printStructs();

  delay(10000);
  Serial.println(F("STARTING AGAIN..."));
}

namespace data {
void push(const byte& a_day, const byte& a_hour, const byte& a_minute, const char* a_text) {
  if (data::structCount < data::maxStructs) {
    structs[data::structCount].day = a_day;
    structs[data::structCount].hour = a_hour;
    structs[data::structCount].minute = a_minute;
    strcpy(structs[data::structCount].text, a_text);
    data::structCount++;
  }
  else {
    for (byte i = 0; i < data::maxStructs - 1; i++) {
      structs[i] = structs[i + 1];
    }
    structs[data::maxStructs - 1].day = a_day;
    structs[data::maxStructs - 1].hour = a_hour;
    structs[data::maxStructs - 1].minute = a_minute;
    strcpy(structs[data::maxStructs - 1].text, a_text);
  }
}

void printStructs() {
  for (const data::record& rec : structs) {
    Serial.print(rec.day);
    Serial.print(F(" "));
    Serial.print(rec.hour);
    Serial.print(F(":"));
    Serial.print(rec.minute);
    Serial.print(F(" "));
    Serial.println(rec.text);
  }
}
}

Thank you Giux that worked nicely! Also, thanks to Idahowalker & KawasakiZx10r for your suggestions, I will look into them too so that I learn. I have noted the size of some of the libraries so share your concerns about them!