Need help initializing Structure - frustrating Friday night

Hello,

I am working on a MIDI footshwitch using an Arduino Mirco.

The footshwitch has 10 buttons and I would like to have 4 pages (i.e. 4 ways to re-assigned the buttons).

For this I create a two structures : one for the buttons, one for the pages
The structure page contains an array of structure buttons

const int NUM_PAGES = 4;
const int NUM_BUTTONS = 10;
const int NUMBER_LED_RING = 6;

const int TIME_LONGPRESS = 500;struct myButton {
  int buttonNumber;                      //Physical position on the board
  int ArduinoPin {8};
  bool buttonPressed {false};       //Was the button Pressed during the loop
  int ShiftRegisterLEDPin[2] {8,8};
  bool colorStatus[2] {LOW, LOW};   //2 because 2 color per button

  Bounce BtnBounce;
  long buttonPressTimeStamp;
  long buttonReleaseTimeStamp;
  bool BtnLongPress {false};


  void setLEDStatus(int color, boolean value) {
      this->colorStatus[color-1]= value;
    }
  bool getLEDStatus(int color){
    return colorStatus[color-1];
  }
  bool isLongPress() {
    if (buttonReleaseTimeStamp - buttonPressTimeStamp > TIME_LONGPRESS) {
        return true;
    }
    else{
	return false;
    }
  }

};

struct myPage {

  int pageNumber {99};
  int HXmode {98};
  struct myButton ListObjButton[NUM_BUTTONS];

  myButton getBtn(int Btn) {
    return ListObjButton[Btn-1];
  }
  void setHXmode(int mode){
    DEBUG_MSG.print("set HXmode to :");
    DEBUG_MSG.print(mode,1);
    DEBUG_MSG.print(" For page Number :");
    DEBUG_MSG.println(this->pageNumber,1);
    this->HXmode = mode;
  }

};

and I gather those into an array as global variable outside of setup and loop.

struct myPage ListObjPage[NUM_PAGES];

When I try to initialize the button, the code is assigning random value stating at pg4 button 8
See the debug print out below:

The code to initialize the button is called from setup()

void initializePages() {

  DEBUG_MSG.println(__func__);
    for (int indexPg = 1; indexPg < NUM_PAGES + 1; indexPg ++){
        ListObjPage[indexPg-1].pageNumber = indexPg;

        switch (indexPg) {
          case 1:
            ListObjPage[indexPg-1].HXmode = SNAP_MODE;
            break;
          case 2:
            ListObjPage[indexPg-1].HXmode = STOMP_MODE;
            break;
          case 3:
            ListObjPage[indexPg-1].HXmode = SCROLL_MODE;
            break;
          case 4:
            ListObjPage[indexPg-1].HXmode = SNAP_MODE;
            break;
        }
        initializeBtn(indexPg);
    }
}

void initializeBtn(int pg) {

  DEBUG_MSG.println(__func__);
  int HXMode = getPage(pg).HXmode;
    for (int indexBtn = 1; indexBtn < NUM_BUTTONS + 1; indexBtn ++){
	**ListObjPage[pg-1].ListObjButton[indexBtn-1].buttonNumber = indexBtn;**
	ListObjPage[pg-1].ListObjButton[indexBtn-1].ArduinoPin = BUTTON_ARDUINO_PINS[indexBtn-1];

	//The first 6 buttons have a LED with 2 color,
	//I am assigning the pin on the shift register for the 2 LED
	if((indexBtn-1)*2 < NUMBER_LED_RING*2 ){

	    ListObjPage[pg-1].ListObjButton[indexBtn-1].ShiftRegisterLEDPin[0] =  LED_PINS[(indexBtn-1)*2];    //color 1 pin
	    ListObjPage[pg-1].ListObjButton[indexBtn-1].ShiftRegisterLEDPin[1] =  LED_PINS[(indexBtn-1)*2+1]; //color 2 pin
	}else{
	    //No LED for this button, I set the PIN to 99
	    DEBUG_MSG.println(indexBtn,1);
	    ListObjPage[pg-1].ListObjButton[indexBtn-1].ShiftRegisterLEDPin[0] = 99;
	    ListObjPage[pg-1].ListObjButton[indexBtn-1].ShiftRegisterLEDPin[1] = 99;
	}

	switch (HXMode) {
	  case STOMP_MODE:
	    ListObjPage[pg-1].ListObjButton[indexBtn-1].setLEDStatus(1, HIGH);
	    break;
	  case SNAP_MODE:
	    if (indexBtn == 6){ListObjPage[pg-1].ListObjButton[indexBtn-1].setLEDStatus(2, HIGH);}
	    else{ListObjPage[pg-1].ListObjButton[indexBtn-1].setLEDStatus(1, HIGH);};
	    break;
	  case SCROLL_MODE:
	      if (indexBtn == 1){ListObjPage[pg-1].ListObjButton[indexBtn-1].setLEDStatus(2, HIGH);}
	      if (indexBtn == 2){ListObjPage[pg-1].ListObjButton[indexBtn-1].setLEDStatus(1, HIGH);}
	      if (indexBtn == 6){ListObjPage[pg-1].ListObjButton[indexBtn-1].setLEDStatus(1, HIGH);}
	      break;
	}
	LEDHaveChanged = true;
    }

}

The line


	*ListObjPage[pg-1].ListObjButton[indexBtn-1].buttonNumber = indexBtn;*

Should setup each button number between 1 and 10 but here is wha I got for page 4 button 8 and onward. It's all garagbade.

I am assuming the array was not set properly but I can't explain where in my code the issue is generated. Very frustrating :frowning:

Button: 7, pg 4
	buttonNumber = 7
	buttonPressed = 0
	Long press status = 1
	ArduinoPin = 8
	Color 1 = 1
	Color 1 Pin = 99
	Color 2 = 0
	Color 2 Pin = 99

Button: 8, pg 4
buttonNumber = 13762**
buttonPressed = 24
Long press status = 1
ArduinoPin = 0
Color 1 = 0
Color 1 Pin = 12544
Color 2 = 0
Color 2 Pin = 4294967221
Button: 9, pg 4
buttonNumber = 1280
buttonPressed = 62
Long press status = 1
ArduinoPin = 2494
Color 1 = 0
Color 1 Pin = 4294961928
Color 2 = 24

Any suggestion.
Note that I am am not very good with C++ so it could be a very simple trivial thing but my lack of experience doesn't point me to the issue...

Thanks for reading

Full code is here (well at least the full code to see the issue, still a lot to code for the project to be done but I can't pass the initialization ...)

//**************************************************************//
//  Name    : Octopus_Version 4
//  Author  :
//  Date    : July 2022 - Modified :
//  Version : 4.02
//  Board   : Arduino Micro
//  Note    : Use the button structure and keep track of LED status
//  	      Based on a project by Stoo //****************************************************************


#include <MIDI.h>
#include <midi_defs.h>
#include <midi_message.h>
#include <midi_namespace.h>
#include <midi_settings.h>
#include <stdlib.h>
#include <Keyboard.h>
#include <Bounce2.h>
#include <Arduino.h>
#include <String.h>

#define DEBUG_MODE true  //set to true for debug output, false for no debug output
#define DEBUG_MSG \
  if (DEBUG_MODE) Serial


const int NUM_PAGES = 4;
const int NUM_BUTTONS = 10;
const int NUMBER_LED_RING = 6;
const int TIME_LONGPRESS = 500;


const int NUM_PIN_ON_SHIFT_REGISTER = 8;
const uint8_t BUTTON_ARDUINO_PINS[NUM_BUTTONS] = {2, 3, 4, 5, 6, 7, 8, 9, A1, A2};
const uint8_t LED_PINS[NUMBER_LED_RING * 2]    = {0,2,1,8,3,8,4,8,5,6,7,8};
//using 8 for LED not hooked, the structure follows button1 color 1,button 1 color 2 etc...




/* Line 6 HX Stomp constants
 * -------------------------
 */

const int STOMP_MODE = 0;
const int SCROLL_MODE = 1;
const int PRESET_MODE = 2;
const int SNAP_MODE = 3;
const int DEFAULT_PROGRAM = 20;

/* Shift register constants
 * ------------------------
 *
 * A TPIC6B595 shift register is used to control the ring LED
 * Those LED are 9V control with a common ground
 * I am using a TPIC6B595 and PNP diodes to deal with the common ground and 9V.
 * 9V is provided directly from ON/OFF switch
 */

const int SER_Pin = 10;   //pin 14 on the TPIC6B595  pin 10 on the Arduino with {color} cable
const int RCLK_Pin = 11;  //pin 12 on the TPIC6B595  pin 11 on the Arduino with cable
const int SRCLK_Pin = 12; //pin 11 on the TPIC6B595  pin 12 on the Arduino with cable


/* Instantiation of the MDI port
 * -----------------------------
 *
 * I am using Serial1 instead of Serial so Serial can be use to output debug messages
 * The MIDI object is called midiOut
 * Forcing the baud rate to 31250 for the MIDI connection.*/


#define UARTE0_BASE_ADDR            0x40002000  // As per nRF52840 Product spec - UARTE
#define UART_BAUDRATE_REG_OFFSET    0x524       // As per nRF52840 Product spec - UARTE
#define UART0_BAUDRATE_REGISTER     (*(( unsigned int *)(UARTE0_BASE_ADDR + UART_BAUDRATE_REG_OFFSET)))
#define BAUD31250                   0x00800000  //31250

MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, midiOut);

/*GLOBAL VARIABLE*/

int  currentPage = 1;
bool LEDHaveChanged = true;
unsigned long loopTime;


/* Structures Definition
 * ---------------------
 */

struct myButton {
  int buttonNumber;                 //Physical position on the board
  int ArduinoPin {8};
  bool buttonPressed {false};       //Was the button Pressed during the loop
  int ShiftRegisterLEDPin[2] {8,8};
  bool colorStatus[2] {LOW, LOW};   //2 because 2 color per button

  Bounce BtnBounce;
  long buttonPressTimeStamp;
  long buttonReleaseTimeStamp;
  bool BtnLongPress {false};


  void setLEDStatus(int color, boolean value) {
      this->colorStatus[color-1]= value;
      //-1 because I want to work with color 1 and color 2
    }
  bool getLEDStatus(int color){
    return colorStatus[color-1];
  }
  bool isLongPress() {
    if (buttonReleaseTimeStamp - buttonPressTimeStamp > TIME_LONGPRESS) {
        return true;
    }
    else{
	return false;
    }
  }

};

struct myPage {

  int pageNumber {99};
  int HXmode {98};
  struct myButton ListObjButton[NUM_BUTTONS];

  myButton getBtn(int Btn) {
    return ListObjButton[Btn-1];
  }
  void setHXmode(int mode){
    DEBUG_MSG.print("set HXmode to :");
    DEBUG_MSG.print(mode,1);
    DEBUG_MSG.print(" For page Number :");
    DEBUG_MSG.println(this->pageNumber,1);
    this->HXmode = mode;
  }

};


struct myPage ListObjPage[NUM_PAGES];



/* Useful functions
 * ---------------- */




struct myPage  getPage(int pageNb) {
  //This function is use so I can work with page number without dealing with the -1 for hte index starting at 0
  return ListObjPage[pageNb-1];
}

struct myButton  getBtn(int BtNb, int pageNb = currentPage) {
  //This function is use so I can work with page number without dealing with the -1 for hte index starting at 0
  return getPage(pageNb).ListObjButton[BtNb-1];
}




/* Printing Functions
 * ------------------
 */
void printBtn(int page){


  for (int indexBtn = 1; indexBtn < NUM_BUTTONS + 1; indexBtn ++){
      DEBUG_MSG.print("\tButton: ");
      DEBUG_MSG.print(indexBtn,1);
      DEBUG_MSG.print(", pg ");
      DEBUG_MSG.println(page,1);
      DEBUG_MSG.print("\t\tbuttonNumber = ");
      DEBUG_MSG.println(ListObjPage[page-1].ListObjButton[indexBtn-1].buttonNumber,1);
      DEBUG_MSG.print("\t\tbuttonPressed = ");
      DEBUG_MSG.println(ListObjPage[page-1].ListObjButton[indexBtn-1].buttonPressed);
      DEBUG_MSG.print("\t\tLong press status = ");
      DEBUG_MSG.println(ListObjPage[page-1].ListObjButton[indexBtn-1].isLongPress());
      DEBUG_MSG.print("\t\tArduinoPin = ");
      DEBUG_MSG.println(ListObjPage[page-1].ListObjButton[indexBtn-1].ArduinoPin);

      for (int indexColor=1; indexColor < 3; indexColor++){
	  DEBUG_MSG.print("\t\tColor ");
	  DEBUG_MSG.print(indexColor,1);
	  DEBUG_MSG.print(" = ");
	  DEBUG_MSG.println(ListObjPage[page-1].ListObjButton[indexBtn-1].getLEDStatus(indexColor));
	  DEBUG_MSG.print("\t\tColor ");
	  DEBUG_MSG.print(indexColor,1);
	  DEBUG_MSG.print(" Pin = ");
	  DEBUG_MSG.println(ListObjPage[page-1].ListObjButton[indexBtn-1].ShiftRegisterLEDPin[indexColor-1],1);

      }

  }

}

void printPage(int pg,bool showBtn = true){
  DEBUG_MSG.print("Page :");
  DEBUG_MSG.println(pg,1);
  DEBUG_MSG.print("\tpageNumber = ");
  DEBUG_MSG.println(getPage(pg).pageNumber,1);
  DEBUG_MSG.print("\tHXmode = ");
  DEBUG_MSG.println(getPage(pg).HXmode,1);
  if (showBtn){ printBtn(pg);}
}

void printPages(bool showBtn = true) {
  //This function print the status of a page - used for debugging.
  for (int indexPg = 1; indexPg < NUM_PAGES + 1; indexPg ++){
      printPage(indexPg,showBtn);
  }
}

/* Initialization Functions
 * -------------------------
 */

void initializePages() {

  DEBUG_MSG.println(__func__);
    for (int indexPg = 1; indexPg < NUM_PAGES + 1; indexPg ++){
        ListObjPage[indexPg-1].pageNumber = indexPg;

        switch (indexPg) {
          case 1:
            ListObjPage[indexPg-1].HXmode = SNAP_MODE;
            break;
          case 2:
            ListObjPage[indexPg-1].HXmode = STOMP_MODE;
            break;
          case 3:
            ListObjPage[indexPg-1].HXmode = SCROLL_MODE;
            break;
          case 4:
            ListObjPage[indexPg-1].HXmode = SNAP_MODE;
            break;
        }
        initializeBtn(indexPg);
    }
}

void initializeBtn(int pg) {

  DEBUG_MSG.println(__func__);
  int HXMode = getPage(pg).HXmode;
    for (int indexBtn = 1; indexBtn < NUM_BUTTONS + 1; indexBtn ++){
	ListObjPage[pg-1].ListObjButton[indexBtn-1].buttonNumber = indexBtn;
	ListObjPage[pg-1].ListObjButton[indexBtn-1].ArduinoPin = BUTTON_ARDUINO_PINS[indexBtn-1];

	//The first 6 buttons have a LED with 2 color,
	//I am assigning the pin on the shift register for the 2 LED
	if((indexBtn-1)*2 < NUMBER_LED_RING*2 ){

	    ListObjPage[pg-1].ListObjButton[indexBtn-1].ShiftRegisterLEDPin[0] =  LED_PINS[(indexBtn-1)*2];    //color 1 pin
	    ListObjPage[pg-1].ListObjButton[indexBtn-1].ShiftRegisterLEDPin[1] =  LED_PINS[(indexBtn-1)*2+1]; //color 2 pin
	}else{
	    //No LED for this button, I set the PIN to 99
	    DEBUG_MSG.println(indexBtn,1);
	    ListObjPage[pg-1].ListObjButton[indexBtn-1].ShiftRegisterLEDPin[0] = 99;
	    ListObjPage[pg-1].ListObjButton[indexBtn-1].ShiftRegisterLEDPin[1] = 99;
	}

	switch (HXMode) {
	  case STOMP_MODE:
	    ListObjPage[pg-1].ListObjButton[indexBtn-1].setLEDStatus(1, HIGH);
	    break;
	  case SNAP_MODE:
	    if (indexBtn == 6){ListObjPage[pg-1].ListObjButton[indexBtn-1].setLEDStatus(2, HIGH);}
	    else{ListObjPage[pg-1].ListObjButton[indexBtn-1].setLEDStatus(1, HIGH);};
	    break;
	  case SCROLL_MODE:
	      if (indexBtn == 1){ListObjPage[pg-1].ListObjButton[indexBtn-1].setLEDStatus(2, HIGH);}
	      if (indexBtn == 2){ListObjPage[pg-1].ListObjButton[indexBtn-1].setLEDStatus(1, HIGH);}
	      if (indexBtn == 6){ListObjPage[pg-1].ListObjButton[indexBtn-1].setLEDStatus(1, HIGH);}
	      break;
	}
	LEDHaveChanged = true;
    }

}


void resetLEDToLOW(){
  DEBUG_MSG.println(__func__);

  for (int indexPg = 1; indexPg < NUM_PAGES+1; indexPg++){
      for (int indexBtn = 1; indexBtn < NUM_BUTTONS+1; indexBtn++){
	  ListObjPage[indexPg-1].ListObjButton[indexBtn-1].setLEDStatus(1, LOW);
	  ListObjPage[indexPg-1].ListObjButton[indexBtn-1].setLEDStatus(2, LOW);
      }
  }
  printPages();
}

int getPinLED(int pin) {
  //NEED REVIEW
  //Return the LED for a given Shift register Pin
  for (int indexPin=0; indexPin < 2* NUMBER_LED_RING + 1; indexPin++) {
      if(LED_PINS[indexPin]==pin){

	  DEBUG_MSG.println(indexPin,1);
	  return indexPin;

      }
  }
  DEBUG_MSG.println("ERROR");
  DEBUG_MSG.println(pin,1);
  return -1;
}

void writeRegisters() {
  //Need to make sure this only change if something has changed.
  DEBUG_MSG.println(__func__);

  if (LEDHaveChanged) {
  digitalWrite(RCLK_Pin, LOW);
  bool value = LOW;
  //For debug
  int color = 0;
  int button = 0;
  for (int indexPin=0; indexPin < NUM_PIN_ON_SHIFT_REGISTER; indexPin++){
        //The pin are from 0 to
        //I can use indexPin to refer to them directly without the need for a lookup table
        digitalWrite(SRCLK_Pin, LOW);
        //Find the button for that Pin
        for (int indexBtn=1;indexBtn < NUM_BUTTONS + 1 ;indexBtn++){
            if(ListObjPage[currentPage -1 ].ListObjButton[indexBtn-1].ShiftRegisterLEDPin[0] == indexPin ){
        	value = ListObjPage[currentPage -1 ].ListObjButton[indexBtn-1].getLEDStatus(1);
        	button = indexBtn;
        	color = 1;
        	break;
            }
            else if (ListObjPage[currentPage -1 ].ListObjButton[indexBtn-1].ShiftRegisterLEDPin[1] == indexPin){
        	value = ListObjPage[currentPage -1 ].ListObjButton[indexBtn-1].getLEDStatus(2);
        	color = 2;
        	button = indexBtn;
        	break;
            }

            else {
        	//The pin is not associated with a LED. I send LOW to the shift register
        	DEBUG_MSG.print("WARNING: PIN ");
                DEBUG_MSG.print(indexPin,1);
        	DEBUG_MSG.print(" on the shift register is not associated with a button.");
        	break;
            }

        }
        digitalWrite(SER_Pin,value);
        digitalWrite(SRCLK_Pin, HIGH);


        //To delete when it works.
        DEBUG_MSG.print("Arduino Pin ");
        DEBUG_MSG.println(indexPin,1);
        DEBUG_MSG.print("\tPage ");
        DEBUG_MSG.println(currentPage,1);
        DEBUG_MSG.print("\tButton ");
        DEBUG_MSG.println(button,1);
        DEBUG_MSG.print("\tColor ");
        DEBUG_MSG.println(color,1);
        DEBUG_MSG.print("\tValue = ");
        DEBUG_MSG.println(value);


  }
  digitalWrite(RCLK_Pin, HIGH);
  LEDHaveChanged = false;
  }
}

void testLEDs(){
 // This function cycles the LED
 //First I save the current status

 // struct myButton currentBtnStatus[NUM_BUTTONS];

  DEBUG_MSG.println(__func__);

  //currentBtnStatus = getPage(currentPage).ListObjButton;
  resetLEDToLOW();
  writeRegisters();
  /*
  for (int indexCol = 1; indexCol < 3;indexCol++) {

      for (int indexBtn = 1; indexBtn < NUM_BUTTONS + 1; indexBtn++){
	     setLED(indexBtn, indexCol, HIGH);
	     writeRegisters();
	     delay(400);
       }
       resetLEDToLOW();
       writeRegisters();


  }

  delay(200);
 // getPage(currentPage).ListObjButton = currentBtnStatus;
*/
}

void readButtons(unsigned long time) {
   int nbOfBtnPressed= 0; //How many button are pressed during this loop
   DEBUG_MSG.println("Reading Button");

   //Read the button and see which ones are pressed.
   for (int indexBtn = 1; indexBtn < NUM_BUTTONS + 1; indexBtn ++) {
       getPage(currentPage).getBtn(indexBtn).buttonPressed = false;

       getPage(currentPage).getBtn(indexBtn).BtnBounce.update();
       if (getPage(currentPage).getBtn(indexBtn).BtnBounce.read() == LOW) {
	   nbOfBtnPressed++;
       }
       if (getPage(currentPage).getBtn(indexBtn).BtnBounce.fell()) {
	   getPage(currentPage).getBtn(indexBtn).buttonPressTimeStamp = time;
	   DEBUG_MSG.print("Btn ");
	   DEBUG_MSG.print(indexBtn,1);
	   DEBUG_MSG.println("was pressed ");
           }

       if (getPage(currentPage).getBtn(indexBtn).BtnBounce.rose()) {
	   getPage(currentPage).getBtn(indexBtn).buttonReleaseTimeStamp = time;
	   getPage(currentPage).getBtn(indexBtn).buttonPressed = true;
	   DEBUG_MSG.print("Btn ");
           DEBUG_MSG.print(indexBtn,1);
	   DEBUG_MSG.println("was released ");


       }
   }
   printPage(currentPage);
}


void setup() {

  DEBUG_MSG.println(__func__);


  /*
   *The pin13 is used to show if the unit is powered.
   *it extends the internal Arduino LED into an external LED.
   *A 220 Ω resistor needs to be added.
   *The LED is located above the ON/OFF switch of the Octopus
  */
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH); //Turning on the status LED


  //Shift register pins.
  pinMode(SER_Pin, OUTPUT);
  pinMode(RCLK_Pin, OUTPUT);
  pinMode(SRCLK_Pin, OUTPUT);

  //Using the Serial for debug messages.
  if (DEBUG_MODE) {
      Serial.begin(9600);
      while (!SerialUSB){
	  ;   //Wait for the serial to connect.
      }
  }
  delay(2000);

  initializePages();

  printPages(true);
  testLEDs();

  //Keyboard is use to control YouTube, GB etc... via a USB cable
  Keyboard.begin();
  DEBUG_MSG.println("Keyboard Initialized");


  Serial1.begin(31250);                // setup serial for MIDI
  UART0_BAUDRATE_REGISTER = BAUD31250; //Apparently there is a bug in the arduino so i have to set the baud rate this way
  DEBUG_MSG.println("MIDI Initialized");


  midiOut.sendProgramChange(DEFAULT_PROGRAM, 1);
  midiOut.sendControlChange(71,SNAP_MODE, 1);


}


void loop(){

  ;
  //Turn on the power status LED.
  //digitalWrite(LED_BUILTIN, HIGH);

  //readButtons(millis());
}





You are defining a struct inside another struct.

The definition of struct myButton should be outside the struct myPage

Same thing with function getBtn() the definition must be outside your struct myPage

Similar thing with struct myButton
You are defining functions inside the struct-definition.
move function definitions to be outside the struct.

If you want to have some functions "inside" of something else you should use classes. Though me personal I don't know how to do that.

best regards Stefan

Struct are declared and are a type. Defining a variable means providing its type for memory allocation.

Besides the fact that the keyword struct is not really needed , there is nothing wrong saying that the myPage class holds an array of myButton class instances.

struct myButton ListObjButton[NUM_BUTTONS];

Did I miss something ?

1 Like

A struct is similar to a class in many ways. You can have functions defined in the struct, it’s not an issue in C++, they will be methods (member functions) you can apply to instances of that struct.

if everything is kinda statically defined, you could assign the values this way

const byte NUM_BUTTONS = 10;

struct Button {
  int buttonNumber;
  int ArduinoPin;
  bool buttonPressed;
};

struct Page {
  byte pageNumber;
  byte hXmode;
  byte buttonCount;
  Button listOfButtons[NUM_BUTTONS];
};

Page listOfPages[] = {
  {0, 99, 3, {{0, 2, false}, {1, 3, false}, {2, 4, false}}},                   // 3 buttons
  {1, 99, 2, {{0, 5, false}, {1, 6, false}}},                                  // 2 buttons
  {2, 99, 1, {{0, 7, false}}},                                                 // 1 button
  {3, 99, 4, {{0, 8, false}, {1, 9, false}, {2, 10, false}, {3, 11, false}}},  // 4 buttons
};

const byte NUM_PAGES = sizeof listOfPages / sizeof * listOfPages;


void setup() {
  Serial.begin(115200); Serial.println();
  for (auto& aPage : listOfPages) {
    Serial.write("{");
    Serial.print(aPage.pageNumber); Serial.write(' ');
    Serial.print(aPage.hXmode); Serial.write(' ');
    Serial.print(aPage.buttonCount); Serial.print(" {");
    for (byte i = 0; i < aPage.buttonCount; i++) {
      Serial.write("{");
      Serial.print(aPage.listOfButtons[i].buttonNumber); Serial.print(", ");
      Serial.print(aPage.listOfButtons[i].ArduinoPin); Serial.print(", ");
      Serial.print(aPage.listOfButtons[i].buttonPressed ? "true} " : "false} " );
    }
    Serial.println("}}");
  }
}

void loop() {}

this should print out all the fields of the listOfPages (not exactly your structure and I did not add the member functions but you should get the idea - and I added a button count in case not all of the 10 buttons are assigned)

Many fields could be made const if you don't plan to change them.

1 Like

What Arduino are you using? It's not an UNO because you use Serial1 and it's not a MEGA because you use SerialUSB. If I use Leonardo I get a low memory warning:

Sketch uses 10054 bytes (35%) of program storage space. Maximum is 28672 bytes.
Global variables use 2547 bytes (99%) of dynamic memory, leaving 13 bytes for local variables. Maximum is 2560 bytes.
Low memory available, stability problems may occur.

Running out of stack space could certainly cause your sketch to produce unexpected results.

There are some worrying warnings in your compilation:

In function 'void readButtons(long unsigned int)':
warning: using temporary as lvalue

getPage(currentPage).getBtn(indexBtn).buttonPressed = false;
                                                           ^~~~~
warning: using temporary as lvalue
getPage(currentPage).getBtn(indexBtn).buttonPressTimeStamp = time;
                                                                    ^~~~
warning: using temporary as lvalue
getPage(currentPage).getBtn(indexBtn).buttonReleaseTimeStamp = time;
                                                                      ^~~~
warning: using temporary as lvalue
getPage(currentPage).getBtn(indexBtn).buttonPressed = true;
                                                             ^~~~

That means you are getting a temporary copy of a struct back from a function and then changing a field in the temporary copy. Your get() functions should return references instead of temporary copies.

In function 'void setup()':
warning: large integer implicitly truncated to unsigned type 
 #define BAUD31250                   0x00800000  //31250
                                     ^
note: in expansion of macro 'BAUD31250'
   UART0_BAUDRATE_REGISTER = BAUD31250; //Apparently there is a bug in the arduino so i have to set the baud rate this way
                             ^~~~~~~~~

The compiler says you are trying to fit a 32-bit integer into a 16-bit register. The result is that you are setting it to zero. I think you have to research this 'fix' a little more.

Hi John,

I am using an Arduino Micro.
I think the one of the issue could indeed be the memory. I didn't realize how quick that get used.

How do I make sure of that ?

Change:
myButton getBtn(int Btn) {
to:
myButton & getBtn(int Btn) {
and change:
struct myPage getPage(int pageNb) {
to:
struct myPage & getPage(int pageNb) {

Then see if those annoying warning messages go away. If you weren't seeing the warning messages, go into Preferences and set "Compiler warnings:" to "All".

@J-ML

Unfortunately most of items in listOfPages will change during the execution (not the pin allocation off-course). That's where I plan on storing the status of the LED when I move from a page to another to ensure returning to a previous page relit the LED as before.
So I want to understand how to do it dynamically. It's also a good learning opportunity for me.
I am learning tons with this bug.

Thanks a lot for the super quick reply

I don't think it will help sufficiently, but look at the data types you're using. You have quite a number of variables using int where byte is likely enough e.g. buttonNumber.

I suspect you're going to need something with more RAM - look at the Teensy for example.

Oops I seems I was a bit too generous with my copy/paste. This was needed when I use another board but I don't think the Micro has the issue I was encountering. I can probably set the MIDI baud rate at 31350 directly. Next step once the buttons are properly initiated.

Good point on the int vs. byte !

I changed to

struct myPage & getPage(byte pageNb) {
  //This function is use so I can work with page number without dealing with the -1 for hte index starting at 0
  return ListObjPage[pageNb-1];
}

struct myButton  & getBtn(byte BtNb, byte pageNb = DEFAULT_PAGE) {
  //This function is use so I can work with page number without dealing with the -1 for hte index starting at 0
  return getPage(pageNb).ListObjButton[BtNb-1];
}

but still get those warnings

In file included from ../sloeber.ino.cpp:32:0:
../Octopus_Micro.ino: In function 'void readButtons(long unsigned int, byte)':
../Octopus_Micro.ino:408:62: warning: using temporary as lvalue [-fpermissive]
getPage(currentPage).getBtn(indexBtn).buttonPressed = false;

any ideas?

Oops... There is a second 'getBtn()' function that is still returning a temporary. When you use that one instead of the myPage::getBtn() you get the same old warning.

struct myButton getBtn(int BtNb, int pageNb = currentPage)

I don't think this is an issue

I got rid of that extra confusing function and it did clean up the error msg.
Thanks again for your help. Greatly appreciated.