Go Down

Topic: Copying a Struct from Program Memory (Read 153 times) previous topic - next topic

cheche_romo

Hi, I'm having trouble when trying to copying data from n arrat of structures declared on program memory.

This is my struct:
Code: [Select]


struct ChordStruct
{
  char *name;
  char *abbreviation;
  uint8_t size;
  uint8_t NotesOffset[7];
};



and this is my struct declaration in Program memory:
Code: [Select]


const ChordStruct Chord[4] PROGMEM =
{
  {MajorStr,         MStr,       uint8_t(3),      uint8_t(0), uint8_t(4), uint8_t(7)},
  {MinorStr,         mStr,       uint8_t(3),      uint8_t(0), uint8_t(3), uint8_t(7)},
  {SeventhStr,       _7Str,      uint8_t(4),      uint8_t(0), uint8_t(4), uint8_t(7), uint8_t(10)},
  {MajorSeventhStr,  maj7Str,    uint8_t(4),      uint8_t(0), uint8_t(4), uint8_t(7), uint8_t(11)},
}



Then I made a set of functions to read from program memory and they work like a charm:

Code: [Select]

String getChordname( uint8_t x)
{
  uint8_t size = strlen_P((char*)pgm_read_word(&(Chord[x].name)));
  uint8_t buffer[size];
  return strcpy_P(buffer, (char*)pgm_read_word(&(Chord[x].name)));
}
String getChordname(ChordStruct *This)
{
  uint8_t size = strlen_P((char*)pgm_read_word(This->name));
  uint8_t buffer[size];
  return strcpy_P(buffer, (char*)pgm_read_word(This->name));
}
String getChordnameAbbv( uint8_t x)
{
  uint8_t size = strlen_P((char*)pgm_read_word(&(Chord[x].abbreviation)));
  uint8_t buffer[size];
  return strcpy_P(buffer, (char*)pgm_read_word(&(Chord[x].abbreviation)));
}
uint8_t getChordSize( uint8_t x)
{
  return pgm_read_byte(&(Chord[x].size));
}
uint8_t getChordNotesOffset(uint8_t x, uint8_t y)
{
  return pgm_read_byte(&(Chord[x].NotesOffset[y]));
}


Now what I am trying is having a pointer to the Chord Struct declared on a global scope

and have this set of functions:

Code: [Select]


void copyChordName(ChordStruct *This, uint8_t x)
{
  This -> name = (char*)(Chord[x].name);
}

void copyChorSize(ChordStruct *This, uint8_t x)
{
  This -> size = (char*)(Chord[x].size);
}
void copyChordMapping(ChordStruct *This, uint8_t x)
{
  uint8_t y = getChordSize(x);
 
  for(uint8_t i = 0; i < y; i++)
  {
    This->NotesOffset[i] = getChordNotesOffset(x,y);
  }
}

void copyChord(ChordStruct *This, uint8_t x)
{
  x = x % ChordCount;
  copyChordName(This,x);
  (This,x);
  copyChordMapping(This,x);
  printCordData(This);
}

void printChordData(ChordStruct *This)
{
    Serial.print(F("Chord name: - "));

    uint8_t size = strlen_P((char*)(&(This->name)));
    uint8_t buffer[size];
    String str = strcpy_P(buffer, (char*)(&(This->name)) );
   
    Serial.print(str);
    Serial.print(F(" - "));

    size = strlen_P((char*)&(This->abbreviation));
    buffer[size];
    str = strcpy_P(buffer, (char*)&(This->abbreviation));
     
    Serial.println(str);
    Serial.println();
   
    uint8_t a = This->size;
    Serial.print(F("Size - "));Serial.println(a);
    Serial.println();
    Serial.print(F("Notes Offset - "));
    for(uint8_t j = 0; j < a ; j++)
    {
        Serial.print(This->NotesOffset[j]);
      if(j < pgm_read_byte(This->size) - 1){ Serial.print(", ");}
    }
    Serial.println();
    Serial.println();
    Serial.println(F("- - - - - - - - - - "));
    Serial.println();
}


what I want to do is to be able to set the chord Struct like this
Code: [Select]


tmpChord = new ChordStruct();
copyChord(tmpChord,x);
printChordData(tmpChord);




maybe one solution would be changing the declaration of the Chord array in progmem to be an array of pointers but I don't know how to do that either.



PaulS

Using PROGMEM to save SRAM, putting the pointers in Flash memory, while keeping the pointed to data in SRAM, doesn't make a lot of sense.

Using PROGMEM to save SRAM, while pissing it away using Strings makes no sense.
The art of getting good answers lies in asking good questions.

cheche_romo

#2
Sep 13, 2017, 03:47 pm Last Edit: Sep 13, 2017, 04:06 pm by cheche_romo
Using PROGMEM to save SRAM, putting the pointers in Flash memory, while keeping the pointed to data in SRAM, doesn't make a lot of sense.

Using PROGMEM to save SRAM, while pissing it away using Strings makes no sense.
I have saved all the strings in progmem...

Code: [Select]

// KeyboardStruct names
const char GlobalTuningStr[]    PROGMEM = "Global Tuning";
const char KeyboardStr[]        PROGMEM = "Keyboard";
const char ChordGeneratorStr[]  PROGMEM = "Chord Generator";

//Chord names Strings
const char MinorStr[]                       PROGMEM = "Minor";
const char SeventhStr[]                     PROGMEM = "Seventh";
const char MajorSeventhStr[]                PROGMEM = "Major Seventh";
const char MinorSeventhStr[]                PROGMEM = "Minor Seventh";
const char SixthStr[]                       PROGMEM = "Sixth";
const char MinorSixthStr[]                  PROGMEM = "Minor Sixth";
const char DiminishedStr[]                  PROGMEM = "Diminished";
const char DiminishedSeventhStr[]           PROGMEM = "Diminished Seventh";
const char HalfDiminishedSeventhStr[]       PROGMEM = "Half Diminished Seventh";
const char AugmentedStr[]                   PROGMEM = "Augmented";
const char AugmentedSeventhStr[]            PROGMEM = "Augmented Seventh";
const char NinthStr[]                       PROGMEM = "Ninth";
const char MajorNinthStr[]                  PROGMEM = "Major Ninth";
const char AddedNinthStr[]                  PROGMEM = "Add Ninth";
const char MinorNinthStr[]                  PROGMEM = "Minor Ninth";
const char EleventhStr[]                    PROGMEM = "Eleventh";
const char MinorEleventhStr[]               PROGMEM = "Minor Eleventh";
const char SeventhSharpEleventhStr[]        PROGMEM = "Seventh Sharp Eleventh";
const char MajorSeventhSharpEleventhStr[]   PROGMEM = "Major Seventh Sharp Eleventh";
const char SeventhSharpNinthStr[]           PROGMEM = "Seventh Sharp Ninth";
const char ThirteenthStr[]                  PROGMEM = "Thirteenth";
const char MajorThirteenthStr[]             PROGMEM = "Major Thirteenth";
const char MinorThirteenthStr[]             PROGMEM = "Minor Thirteenth";
const char SuspendedFourthStr[]             PROGMEM = "Suspended Fourth";
const char SuspendedSecondStr[]             PROGMEM = "Suspended Second";
const char PowerChordStr[]                  PROGMEM = "Power Chord";
const char SeventhSharpFifthStr[]           PROGMEM = "Seventh Sharp Fifth";

// Chord names abbreviations Strings
const char MStr[]       PROGMEM = "M";
const char mStr[]       PROGMEM = "m";
const char _7Str[]      PROGMEM = "7";
const char maj7Str[]    PROGMEM = "maj7";
const char min7Str[]    PROGMEM = "min7";
const char _6Str[]      PROGMEM = "6";
const char min6Str[]    PROGMEM = "min6";
const char dimStr[]     PROGMEM = "dim";
const char dim7Str[]    PROGMEM = "dim7";
const char min7b5Str[]  PROGMEM = "min7b5";
const char augStr[]     PROGMEM = "aug";
const char aug7Str[]    PROGMEM = "aug7";
const char _9Str[]      PROGMEM = "9";
const char maj9Str[]    PROGMEM = "maj9";
const char add9Str[]    PROGMEM = "add9";
const char min9Str[]    PROGMEM = "min9";
const char _11Str[]     PROGMEM = "11";
const char min11Str[]   PROGMEM = "min11";
const char _7S11Str[]   PROGMEM = "7#11";
const char maj7S11Str[] PROGMEM = "maj7#11";
const char _7S9Str[]    PROGMEM = "7#9";
const char _13Str[]     PROGMEM = "13";
const char maj13Str[]   PROGMEM = "maj13";
const char min13Str[]   PROGMEM = "min13";
const char sus4Str[]    PROGMEM = "sus4";
const char sus2Str[]    PROGMEM = "sus2";
const char _5Str[]      PROGMEM = "5";
const char _7S5Str[]    PROGMEM = "7#5";


I only need one instance of the ChordStruct declared on the SRAM, that is what I have, what I need is to make a copy of the desired chord that is stored in program memory to the chord variable in SRAM, so I can then use the data.

I need to make a copy of the data stored on Program memory, why does not makes sense to have strings declared in program memory?


PaulS

Quote
why does not makes sense to have strings declared in program memory?
It does. But the snippets you originally posted did not show that that was the case.

You are still pissing away memory using Strings. Stop that.
The art of getting good answers lies in asking good questions.

cheche_romo

#4
Sep 13, 2017, 04:07 pm Last Edit: Sep 13, 2017, 04:12 pm by cheche_romo
It does. But the snippets you originally posted did not show that that was the case.

You are still pissing away memory using Strings. Stop that.
What is a better way to handle text data?? :)

Also My original question, how can I copy the data on the Structure array that is in the progam memory to the Structure declared global? , for example the char pointer "name"

jremington

#5
Sep 13, 2017, 04:12 pm Last Edit: Sep 13, 2017, 04:16 pm by jremington
Use character arrays to store character data (C strings). There is a comprehensive set of small, very efficient functions to manipulate them and they don't trash memory if used correctly.

memcpy() and strcpy() should be useful in your case.

cheche_romo

Use character arrays to store character data (C strings). There is a comprehensive set of small, very efficient functions to manipulate them and they don't trash memory if used correctly.
Great!, thanks.

johnwasser

As just a style note, there is no need to cast integer constants when you use them to initialize a variable.  The compiler knows to do that and can warn you if the casting would cause problems.
Code: [Select]
const ChordStruct Chord[4] PROGMEM =
{
  {MajorStr,         MStr,       3,      0, 4, 7},
  {MinorStr,         mStr,       3,      0, 3, 7},
  {SeventhStr,       _7Str,      4,      0, 4, 7, 10},
  {MajorSeventhStr,  maj7Str,    4,      0, 4, 7, 11},
}


Note: If the first element of your offset array is always ZERO you can save some space by not storing it in the array.
Send Bitcoin tips to: 1G2qoGwMRXx8az71DVP1E81jShxtbSh5Hp

PaulS

Quote
memcpy() and strcpy() should be useful in your case.
There are also memcpy_P() and strcpy_P() that bear looking into.
The art of getting good answers lies in asking good questions.

cheche_romo

#9
Sep 13, 2017, 08:02 pm Last Edit: Sep 13, 2017, 08:40 pm by cheche_romo
Well, after struggling all day long this is what I came up with:

memcpy didn't worked for me, so I did this function:

Code: [Select]


void fillChord( ChordStruct *ThisChord, uint8_t buttonPressed)
{
  uint8_t _Chord = buttonPressed%ChordCount;
  ThisChord -> name = getChordName(_Chord);
  ThisChord -> size = getChordSize(_Chord);
  for(uint8_t i = 0; i < ThisChord -> size; i++)
  {
    ThisChord->NotesOffset[i] = getChordNotesOffset(_Chord,i);
  }
}

char* getChordName( uint8_t x)
{
  return pgm_read_word((Chord[x].name));
}

uint8_t getChordSize( uint8_t x)
{
  return pgm_read_byte(&(Chord[x].size));
}

uint8_t getChordNotesOffset(uint8_t x, uint8_t y)
{
  return pgm_read_byte(&(Chord[x].NotesOffset[y]));
}



but I can't get the name char pointer on the tmpString struct to be the one on the Program Memory.

I tried printing it with:
Code: [Select]

uint8_t getChordNotesOffset(uint8_t x, uint8_t y)
{
  return pgm_read_byte(&(Chord[x].NotesOffset[y]));
}


but the serial monitor only gets trash output.

why can't I just do:

Code: [Select]


void fillChord( ChordStruct *ThisChord, uint8_t buttonPressed)
{
  uint8_t _Chord = buttonPressed%ChordCount;

  ThisChord -> name = pgm_read_ptr(Chord[_Chord].name);

}


jremington

Quote
There are also memcpy_P() and strcpy_P()
Thanks, didn't know about those! Very useful!

PaulS

Quote
I tried printing it with:
Why would you expect that a pointer in progmem would point to SRAM? Storing the pointers in PROGMEM but the strings (what is pointed to) in SRAM would not make sense.

If the pointer is in PROGMEM and what is pointed to is also in PROGMEM, then you need to get the pointer (as you are doing) from PROGMEM, and then get the pointed to data from PROGMEM.
The art of getting good answers lies in asking good questions.

Go Up