Storing and accessing stuff from PROGMEM

I need a little help storing and accessing data from PROGMEM, any hint will help a lot. Imagine you have:

struct part
{
  byte width;
  byte total_data;
  byte *data;
};

Where data amount is variable:

part part1 = {3,2,(byte[]){100,100}};
part part2 = {3,3,(byte[]){100,100,100}};

And then:

struct assembly
{
  byte width;
  byte height;
  byte total_parts;
  part *parts;
};

Where parts length is also variable:

assembly assembly1 = {3,4,2,(part[]){part1,part2}};

How could I store that in PROGMEM? should I change the structure?

Something like this? It’s going to be annoying to work with.

struct part
{
  byte width;
  byte total_data;
  const byte *data;
};
const byte data1[] PROGMEM = {100,100};
part part1 = {3,2,data1};
part part2 = {3,3,data1};

struct assembly
{
  byte width;
  byte height;
  byte total_parts;
  const part *parts;
};

const part parts[] PROGMEM = {part1,part2};

const assembly assembly1 PROGMEM = {3,4,2,parts};

It depends on how you’re intending to use the structures.

If you’re planning to read it out into memory some how so the pointers are pointers to RAM, that’s going to need a different response to if you want to keep everything in progmem.

If you want to keep everything in progmem, you’ll have to store the byte arrays separately.

You might want to try something like this for handling the arrays:

class ProgmemByteArray
{
private:
	uint8_t const * address;
	uint8_t amount;

public:
        contexpr ProgmemArray(void) = default;
	contexpr ProgmemArray(uint8_t * address, uint8_t amount) : address(address), amount(amount) {}
	
	contexpr uint8_t const * getAddress(void) const
	{
		return this->address;
	}
	
	contexpr uint8_t getAmount(void) const
	{
		return this->amount;
	}
	
	// slow but safe
	bool tryGet(int index, uint8_t & output) const
	{
		if(address == nullptr)
			return false;
		if(amount == 0)
			return false;
		if(index >= amount)
			return false;
	
		output = static_cast<uint8_t>(pgm_read_byte(&address[index]));
		return true;
	}
	
	// fast but unsafe
	uint8_t operator [](int index) const
	{
		return static_cast<uint8_t>(pgm_read_byte(&address[index]));
	}
};

Which can be used as a sort of proxy and treated like a real array through the index operator.

1 Like

Thanks both, I will give it some extra thoughts… c# spoiled me, so when I am back to arduino I feel like in a desert island after living in the city for 30 years :stuck_out_tongue:

This post explains so much, thanks.

Really?

It was kind of a rushed response because I was half expecting a “my exact use case is this:” or a bit more detail so I could provide more suggestions.
(I just updated it because I forgot to check for nullptr. And normally I’d use explicit this-> to differentiate between members and arguments.)


Out of interest, the class I threw together could be turned into a template so it could be used with more types, I’ve already got part of the system that would be needed to do that (specifically a generic ‘read almost anything from progmem’ function).

1 Like