Access to data in PROGMEM structure (two dimensional)

I have a problem,
In a .h file, a PROGMEM structure is define.
A complete example :

typedef uint8_t VT_PSTYLE;
#define VT_PSTYLE_TEXT_LEN 4

const ValueTitle<VT_PSTYLE, VT_PSTYLE_TEXT_LEN> PStyleTitles PROGMEM =
{
{0x21, {‘U’,‘s’,‘1’,0} },
{0x22, {‘U’,‘s’,‘2’,0} },
{0x23, {‘U’,‘s’,‘3’,0} },
{0x81, {‘S’,‘t’,‘d’,0} },
{0x82, {‘P’,‘r’,‘t’,0} },
{0x83, {‘L’,‘n’,‘d’,0} },
{0x84, {‘N’,‘t’,‘l’,0} },
{0x85, {‘F’,‘t’,‘h’,0} },
{0x86, {‘M’,‘o’,‘n’,0} }
};

#define VT_PSTYLE_COUNT sizeof(PStyleTitles) / (sizeof(VT_PSTYLE) + VT_PSTYLE_TEXT_LEN)

I have an input string data is “Lnd”

I want find the hexa value corresponding to “Lnd” ?

And if possible, I want find the index in the list (example position 6 in the list) ?

I have search on google and forum for help with PROGMEM but all example is for one dimensional array, but in this case is a two dimensional array.

Have you an example based on this array, to acces of the data of the first column by a request on the second column ?

Many thanks by advance,
Regards ThierryD

What is the definition of the ValueTitle template?

this is the template :

template <class ValueType, const uint8_t TitleSize>
struct ValueTitle
{
ValueType value;
const char title[TitleSize];
};

Help me, please ...

So you have a string in PROGMEM and you want to compare it to a string in SRAM. I think the strcmp_P(sram, progmem) will do that. I think the code would look something like this:

unsigned char lookupValue(char *t) {
  for (int i=0; i< VT_PSTYLE_COUNT; i++)
    if (strcmp_P(t, &PStyleTitles[i].title) == 0)
      return pgm_read_byte_near(&PStyleTitles[i].value);
  return 0;  // If no match is found
}

Hi John,
many many thanks,
that’s the good way (I am sure),
but I have an error and I am not a good user of pointer and strcmp.

For use your code I write :

char S = lookupValue("Lnd");
Serial.println(S);

But I have an error :
NKRemote.cpp: In function ‘unsigned char lookupValue(char*)’:
NKRemote:438: error: cannot convert ‘const char ()[4]’ to 'const prog_char’ for argument ‘2’ to ‘int strcmp_P(const char*, const prog_char*)’

I don’t now why

For test, I have use this (and that’s works fine for read all value):

void lookupValue() {
  for (int i=0; i< VT_PSTYLE_COUNT; i++)
  {
      Serial.println(pgm_read_byte_near(&PStyleTitles[i].value));
  }
}

And I get all the list in the Serial Monitor (That’s good for the moment)
But if I want to get the title with :

Serial.println((String)pgm_read_word(&PStyleTitles[ i ].title)); 
or Serial.println((char*)PStyleTitles[ i ].title);

I have not the title.

If I read the title in a string, I can use other method to compare it with a reference string and get the value and the index.
Can you help me ?

You are only reading two bytes ( pgm_read_word )

Serial.println((String)pgm_read_word(&PStyleTitles[ i ].title)); 
or Serial.println((char*)PStyleTitles[ i ].title);

The serial library has support for progmem strings:

Serial.println( ( __FlashStringHelper* ) &PStyleTitles[ i ].title );

Or if you want the data yourself you can use strcpy_P to retrieve the text to sram.

Many thanks for your help,

the code

Serial.println( ( __FlashStringHelper* ) &PStyleTitles[ i ].title );

works very fine.

But if I want to store the result in a string (not the serial port), Have you an example with strcpy_P ?

I am not a good user of pointer (I work, I work, ...) Thanks

Maybe something like that?

strcpy_P( buffer, (PGM_P)pgm_read_word( &(PStyleTitles[ i ].title) ) );

Many many thanks to you two for your help.
I have now all solution for works.

for read the tilte in a string I have use that :

char bufferX[4];
strcpy_P(bufferX, PStyleTitles[i].title);
Serial.println(bufferX);

For all users, the complete test code to get the title and the value (and i is the index) :

void lookupValue() {
  for (int i=0; i< VT_PSTYLE_COUNT; i++)
  {
    char bufferX[4];
    strcpy_P(bufferX, PStyleTitles[i].title);
    Serial.println(bufferX);
    Serial.println(pgm_read_byte_near(&PStyleTitles[i].value));
  }
}

Many thanks again
Problem is solved

You will have problems with that:

strcpy_P(bufferX, PStyleTitles[i].title);

Use the thing I posted, I'm not sure it's the correct way to do it, but I know it works perfect.

A little end question.

if my value is stored like this : 0x000493E0 or 0xFFFFFFFF

the line Serial.println(pgm_read_byte_near(&PStyleTitles*.value)); can't read this because byte_near is one byte.* What pgm_read ... I do to use for read a data who is 0xFFFFFFFF Thanks

I have found (search in Google)

it is

Serial.println(pgm_read_dword(&ShutterSpeedTitles[i].value));

A new end little question (the very end)

This function works fine

void lookupValue() {
  for (int i=0; i< VT_PSTYLE_COUNT; i++)
  {
    char bufferX[4];
    strcpy_P(bufferX, PStyleTitles[i].title);
    Serial.println(bufferX);
    Serial.println(pgm_read_byte_near(&PStyleTitles[i].value));
  }
}

but if now I want to pass parameters to use the same function for many list (same structure)

what is the best to pass thePStyleTitles in parameters ?

It is to do that :

void lookupValue(int LIST_COUNT, int TEXT_LEN, ????????) {
  for (int i=0; i< LIST_COUNT; i++)
  {
    char bufferX[TEXT_LEN];
    strcpy_P(bufferX, ????????[i].title);
    Serial.println(bufferX);
    Serial.println(pgm_read_byte_near(&????????[i].value));
  }
}

The ??? is my problem to transfert pointer and it is the list.

Use a pointer to pass the array:

void lookupValue(int LIST_COUNT, int TEXT_LEN, ValueTitle<VT_PSTYLE, VT_PSTYLE_TEXT_LEN> *v_Ptr ) {
  for (int i=0; i< LIST_COUNT; i++)
  {
    char bufferX[TEXT_LEN];
    strcpy_P(bufferX, v_Ptr[i].title);
    Serial.println(bufferX);
    Serial.println(pgm_read_byte_near(&v_Ptr[i].value));
  }
}

Or for ease of use with the template type:

typedef ValueTitle<VT_PSTYLE, VT_PSTYLE_TEXT_LEN> VTT;

void lookupValue(int LIST_COUNT, int TEXT_LEN, VTT *v_Ptr ) {
  for (int i=0; i< LIST_COUNT; i++)
  {
    char bufferX[TEXT_LEN];
    strcpy_P(bufferX, v_Ptr[i].title);
    Serial.println(bufferX);
    Serial.println(pgm_read_byte_near(&v_Ptr[i].value));
  }
}

Many thanks at all for your answers

Regards.