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!

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