Using source code for configuration of large arrays

The project is a MIDI controller. It has 6 buttons. The user can configure up to 6 MIDI commands to be sent by each button. In addition, the controller has 12 virtual banks which load each button with a new set of MIDI commands. Each command is saved in external EEPROM as an 8-byte array.

Picture of prototype:

Eventually the MIDI controller will have some sort of interface for configuration, but in the meantime, I am using a separate Arduino sketch to update the EEPROM when a configuration change is required. There isn't enough flash memory to do both in one sketch. So the EEPROM-load sketch is loaded to the controller when the configuration requires updating. Otherwise the MIDI controller sketch is loaded for actual use of the device.

The desired scenario is that the source code is formatted in a fashion that makes it easy to navigate to the right button and update the right 8-byte array.

Example:

/*pseudo code for conceptual purposes. Not intended to compile */

const int numPages    = 12;
const int numButtons  = 6;
const int numActions  = 6;

byte b[numPages][numButtons][numActions];

//================================================ PAGE 1 ===============================================
p = 1;
/*-------Top Left -------------     ---------Top Middle------------     ---------Top Right------------*/

b[p][4][1] = {PC,0,BS,0,0,0,0,0};   b[p][5][1] = {PC,1,HX,0,0,0,0,0};   b[p][6][1] = {PC,2,HX,0,0,0,0,0};
b[p][4][2] = {PC,0,HX,0,0,0,0,0};   b[p][5][2] = {PC,2,TL,0,0,0,0,0};   b[p][6][2] = {PC,4,TL,0,0,0,0,0};
b[p][4][3] = {PC,0,TL,0,0,0,0,0}    b[p][5][3] = {PC,3,BS,0,0,0,0,0};   b[p][6][3] = {PC,6,BS,0,0,0,0,0};
b[p][4][4] = {XX,0,0,0,0,0,0,0};    b[p][5][4] = {XX,0,0,0,0,0,0,0};    b[p][6][4] = {XX,0,0,0,0,0,0,0};
b[p][4][5] = {XX,0,0,0,0,0,0,0};    b[p][5][5] = {XX,0,0,0,0,0,0,0};    b[p][6][5] = {XX,0,0,0,0,0,0,0};
b[p][4][6] = {XX,0,0,0,0,0,0,0};    b[p][5][6] = {XX,0,0,0,0,0,0,0};    b[p][6][6] = {XX,0,0,0,0,0,0,0};

/*-------Bottom Left-----------     ---------Bottom Middle----------     ---------Bottom Right---------*/

b[p][1][1] = {XX,0,0,0,0,0,0,0};    b[p][2][1] = {XX,0,0,0,0,0,0,0};    b[p][3][1] = {XX,0,0,0,0,0,0,0};
b[p][1][2] = {XX,0,0,0,0,0,0,0};    b[p][2][2] = {XX,0,0,0,0,0,0,0};    b[p][3][2] = {XX,0,0,0,0,0,0,0};
b[p][1][3] = {XX,0,0,0,0,0,0,0};    b[p][2][3] = {XX,0,0,0,0,0,0,0};    b[p][3][3] = {XX,0,0,0,0,0,0,0};
b[p][1][4] = {XX,0,0,0,0,0,0,0};    b[p][2][4] = {XX,0,0,0,0,0,0,0};    b[p][3][4] = {XX,0,0,0,0,0,0,0};
b[p][1][5] = {XX,0,0,0,0,0,0,0};    b[p][2][5] = {XX,0,0,0,0,0,0,0};    b[p][3][5] = {XX,0,0,0,0,0,0,0};
b[p][1][6] = {XX,0,0,0,0,0,0,0};    b[p][2][6] = {XX,0,0,0,0,0,0,0};    b[p][3][6] = {XX,0,0,0,0,0,0,0};


//================================================ PAGE 2 ===============================================
p = 2;

/*-------Top Left -------------     ---------Top Middle------------     ---------Top Right------------*/
b[p][4][1] = {PC,3,HX,0,0,0,0,0};   b[p][5][1] = {PC,4,HX,0,0,0,0,0};   b[p][6][1] = {PC, 5,HX,0,0,0,0,0};
b[p][4][2] = {PC,6,TL,0,0,0,0,0};   b[p][5][2] = {PC,8,TL,0,0,0,0,0};   b[p][6][2] = {PC,10,TL,0,0,0,0,0};
b[p][4][3] = {PC,9,BS,0,0,0,0,0};   b[p][5][3] = {PC,12,BS,0,0,0,0,0};  b[p][6][3] = {PC,15,BS,0,0,0,0,0};
b[p][4][4] = {XX,0,0,0,0,0,0,0};    b[p][5][4] = {XX,0,0,0,0,0,0,0};    b[p][6][4] = {XX,0,0,0,0,0,0,0};
b[p][4][5] = {XX,0,0,0,0,0,0,0};    b[p][5][5] = {XX,0,0,0,0,0,0,0};    b[p][6][5] = {XX,0,0,0,0,0,0,0};
b[p][4][6] = {XX,0,0,0,0,0,0,0};    b[p][5][6] = {XX,0,0,0,0,0,0,0};    b[p][6][6] = {XX,0,0,0,0,0,0,0};

/*-------Bottom Left-----------     ---------Bottom Middle----------     ---------Bottom Right---------*/
b[p][1][1] = {XX,0,0,0,0,0,0,0};    b[p][2][1] = {XX,0,0,0,0,0,0,0};    b[p][3][1] = {XX,0,0,0,0,0,0,0};
b[p][1][2] = {XX,0,0,0,0,0,0,0};    b[p][2][2] = {XX,0,0,0,0,0,0,0};    b[p][3][2] = {XX,0,0,0,0,0,0,0};
b[p][1][3] = {XX,0,0,0,0,0,0,0};    b[p][2][3] = {XX,0,0,0,0,0,0,0};    b[p][3][3] = {XX,0,0,0,0,0,0,0};
b[p][1][4] = {XX,0,0,0,0,0,0,0};    b[p][2][4] = {XX,0,0,0,0,0,0,0};    b[p][3][4] = {XX,0,0,0,0,0,0,0};
b[p][1][5] = {XX,0,0,0,0,0,0,0};    b[p][2][5] = {XX,0,0,0,0,0,0,0};    b[p][3][5] = {XX,0,0,0,0,0,0,0};
b[p][1][6] = {XX,0,0,0,0,0,0,0};    b[p][2][6] = {XX,0,0,0,0,0,0,0};    b[p][3][6] = {XX,0,0,0,0,0,0,0};

/* continues for ~12 pages */ 

void setButton(int page, int button, int actionNum, byte action[8]){
	page--;		//zero-based index to 1-based convention
	button--;
	actionNum--; 

	/* Calculate the address to write the configuration to */
	int addr = 0
	+ (page   * BytesPerPage)
	+ (button * BytesPerButton)
	+ (actionNum * BytesPerAction);
	
	/* Write the configuration to external EEPROM */
	int status = eep.write(addr, action, 8);
}

void setup(void)
{
	
	//Loop through pages
	for (p=1; p<=numPaged; p++){
		
		//Loop through buttons
		for (int b=1; b <=numButtons;b++){		
	
		    //Loop through button actions
		    for (a=1; a<=numActions; a++){
			    setButton(p, b, a, b[p][b][a]); //Write the button config to external EEPROM
		    }
	    }
	}
	
}

void loop(){
	
}

Of course this doesn't work because C doesn't allow setting arrays like this outside of the initial declaration. What are some other options for accomplishing the task.

For reference, the MIDI controller code is here, still very much a work in progress:

Delta_G:
I stopped there. Humans who can't handle zero based counting shouldn't be messing with source code. Coders who want other coders to help with code shouldn't do things that make it harder for coders to follow.

OK I removed the unconventional indexing so that you would be able to read the code without undue difficulty.

Using six OLED displays is going to push the memory capability of many Arduinos. What sort are you going to use?

Grumpy_Mike:
Using six OLED displays is going to push the memory capability of many Arduinos. What sort are you going to use?

I'm using a Nano. The MIDI sketch is already working although it only leaves 289 bytes of dynamic memory. That's without any serious optimization. I'm using a 256Kb I2C EEPROM to store the configuration.

I also have a ESP32-WROOM that I may port the project to eventually.

Well you definitely can’t run six displays of that sort with a nano, even with no other code.

Grumpy_Mike:
Well you definitely can’t run six displays of that sort with a nano, even with no other code.

I'm actually doing it. I've used this MIDI pedal for live gigs a couple of times now. There are no issues driving the displays.

iyDrJUk:

/*pseudo code for conceptual purposes. Not intended to compile */

That makes it a waste of time to even look at.

Of course this doesn't work because C doesn't allow setting arrays like this outside of the initial declaration. What are some other options for accomplishing the task.

Of course you can, you just have to correct syntax.

uint8_t i[][] = {{1, 2}, {3, 4}};

Placing this stuff in PROGMEM will also help a lot.

wvmarle:
Of course you can, you just have to correct syntax.

uint8_t i[][] = {{1, 2}, {3, 4}};

Did you paste the wrong code by accident? This is an initial declaration, no? How does it demonstrate the assignment of multiple elements of an array outside of initial declaration? Perhaps I am missing your point.

That's how you declare a multi-dimensional array, which appeared what you were asking for, but then your question was pretty ambiguous and posting pseudo-code is not helping either.

If you later want to assign values to an array you have to do that one by one (use for loops).

wvmarle:
That's how you declare a multi-dimensional array, which appeared what you were asking for...

I'm not sure what part of my post would make someone think this since:

  1. The included code contains a proper multi-dimensional array declaration demonstrating that the author understands this concept
  2. This isn't the correct sub-forum for asking that question

As for posting pseudo-code, I'm not sure how one posts an implementation when there is not yet a conceptual approach defined. Perhaps whatever interface you are using doesn't clearly indicate that this thread is in the
"Project Guidance" sub-forum with the stated purpose of discussing "Advice on general approaches or feasibility".

Keeping the data formatting somewhat near the example you gave in the original post makes it a bit complicated, but after looking over your code you could do something like this:

typedef struct {
  char displayTextTop [strStringsPerButton ][numButtons / 2][strBytesPerString];
  byte buttonActionsTop [numActions][numButtons / 2][action_size];
  char displayTextBottom [strStringsPerButton ][numButtons / 2][strBytesPerString]; 
  byte buttonActionsBottom [numActions][numButtons / 2][action_size]; 
} initializationDataType;

const initializationDataType initializationData[numPages] PROGMEM = 
{
//======================== PAGE 0 ==============================

{{
//----Top Left-----     ---Top Middle-----     ---Top Right------
{{"Song     "},         {"Song    "},          {"Song    "}},
{{"1        "},         {"2       "},          {"3       "}}},
{
{{PC,0,BS,0,0,0,0,0},   {PC,1,HX,0,0,0,0,0},   {PC,2,HX,0,0,0,0,0}},
{{PC,0,HX,0,0,0,0,0},   {PC,2,TL,0,0,0,0,0},   {PC,4,TL,0,0,0,0,0}},
{{PC,0,TL,0,0,0,0,0},   {PC,3,BS,0,0,0,0,0},   {PC,6,BS,0,0,0,0,0}},
{{XX,0,0,0,0,0,0,0},    {XX,0,0,0,0,0,0,0},    {XX,0,0,0,0,0,0,0}},
{{XX,0,0,0,0,0,0,0},    {XX,0,0,0,0,0,0,0},    {XX,0,0,0,0,0,0,0}},
{{XX,0,0,0,0,0,0,0},    {XX,0,0,0,0,0,0,0},    {XX,0,0,0,0,0,0,0}}},

{
//---Bottom Left---    ---Bottom Middle---    ---Bottom Right----
{{"Hold for"},          {"This Pedal"},        {"Hold to Return"}},
{{"Tuner   "},          {"Is Awesome"},        {"To Preset 1  "}}},
{
{{XX,0,0,0,0,0,0,0},    {XX,0,0,0,0,0,0,0},    {XX,0,0,0,0,0,0,0}},
{{XX,0,0,0,0,0,0,0},    {XX,0,0,0,0,0,0,0},    {XX,0,0,0,0,0,0,0}},
{{XX,0,0,0,0,0,0,0},    {XX,0,0,0,0,0,0,0},    {XX,0,0,0,0,0,0,0}},
{{XX,0,0,0,0,0,0,0},    {XX,0,0,0,0,0,0,0},    {XX,0,0,0,0,0,0,0}},
{{XX,0,0,0,0,0,0,0},    {XX,0,0,0,0,0,0,0},    {XX,0,0,0,0,0,0,0}},
{{XX,0,0,0,0,0,0,0},    {XX,0,0,0,0,0,0,0},    {XX,0,0,0,0,0,0,0}}}},

That does set all the data in the array declaration, but it will be a bit easier to keep track of if you put the array declaration in a separate file, and #include it in your sketch.

iyDrJUk:
2) This isn't the correct sub-forum for asking that question

A new poster actually taking extreme care in that matter is not something I have come to expect. Assuming the stated forum topic to be part of the question background even less so.

UPDATE: I have had some success using an external tool to encode each 8-byte configuration as a uint64_t which can then be copy/pasted into the sketch where it gets casts as a byte array (using __builtin_bswap64) and written to the external EEPROM.

david_2018:
Keeping the data formatting somewhat near the example you gave in the original post makes it a bit complicated, but after looking over your code you could do something like this:

typedef struct {

char displayTextTop [strStringsPerButton ][numButtons / 2][strBytesPerString];
  byte buttonActionsTop [numActions][numButtons / 2][action_size];
  char displayTextBottom [strStringsPerButton ][numButtons / 2][strBytesPerString];
  byte buttonActionsBottom [numActions][numButtons / 2][action_size];
} initializationDataType;

const initializationDataType initializationData[numPages] PROGMEM =
{
//======================== PAGE 0 ==============================

{{
//----Top Left-----    ---Top Middle-----    ---Top Right------
{{"Song    "},        {"Song    "},          {"Song    "}},
{{"1        "},        {"2      "},          {"3      "}}},
{
{{PC,0,BS,0,0,0,0,0},  {PC,1,HX,0,0,0,0,0},  {PC,2,HX,0,0,0,0,0}},
{{PC,0,HX,0,0,0,0,0},  {PC,2,TL,0,0,0,0,0},  {PC,4,TL,0,0,0,0,0}},
{{PC,0,TL,0,0,0,0,0},  {PC,3,BS,0,0,0,0,0},  {PC,6,BS,0,0,0,0,0}},
{{XX,0,0,0,0,0,0,0},    {XX,0,0,0,0,0,0,0},    {XX,0,0,0,0,0,0,0}},
{{XX,0,0,0,0,0,0,0},    {XX,0,0,0,0,0,0,0},    {XX,0,0,0,0,0,0,0}},
{{XX,0,0,0,0,0,0,0},    {XX,0,0,0,0,0,0,0},    {XX,0,0,0,0,0,0,0}}},

{
//---Bottom Left---    ---Bottom Middle---    ---Bottom Right----
{{"Hold for"},          {"This Pedal"},        {"Hold to Return"}},
{{"Tuner  "},          {"Is Awesome"},        {"To Preset 1  "}}},
{
{{XX,0,0,0,0,0,0,0},    {XX,0,0,0,0,0,0,0},    {XX,0,0,0,0,0,0,0}},
{{XX,0,0,0,0,0,0,0},    {XX,0,0,0,0,0,0,0},    {XX,0,0,0,0,0,0,0}},
{{XX,0,0,0,0,0,0,0},    {XX,0,0,0,0,0,0,0},    {XX,0,0,0,0,0,0,0}},
{{XX,0,0,0,0,0,0,0},    {XX,0,0,0,0,0,0,0},    {XX,0,0,0,0,0,0,0}},
{{XX,0,0,0,0,0,0,0},    {XX,0,0,0,0,0,0,0},    {XX,0,0,0,0,0,0,0}},
{{XX,0,0,0,0,0,0,0},    {XX,0,0,0,0,0,0,0},    {XX,0,0,0,0,0,0,0}}}},




That does set all the data in the array declaration, but it will be a bit easier to keep track of if you put the array declaration in a separate file, and #include it in your sketch.

I like this solution!

iyDrJUk:
I'm actually doing it. I've used this MIDI pedal for live gigs a couple of times now. There are no issues driving the displays.

So what library are you using for this?

  1. This isn't the correct sub-forum for asking that question

No matter where you post you still get the same old farts answering you. :wink:

Grumpy_Mike:
So what library are you using for this?

U8glib

I started out with U8g2lib and honestly forgot what the issue was that caused me to revert to U8glib.

Source code for the normal operation of the project is here:

I'm using a global 382-byte array to store the display text. Although that could probably be cut in half by limiting each line of text to 16 characters. If need be, I can get rid of the global array altogether, I am only using it because I thought of making the text dynamic, e.g., invert the colors to indicate the toggle state of a switch.

Thanks, I will look into that one.