Writing to EEPROM using structs within structs

Hi there,

I can successfully write to EEPROM using a struct pointer, but I am stuck with using structs within the main struct to group the data, as I keep hitting a compile error brick wall.

I wanted to be able to point to an inner struct and still read & write data for it's members into the correct locations in EEPROM. I could not find a way to reference the inner struct in a struct pointer and have it compile, using either "->" or ".". Perhaps I am overreaching, any guidance would be greatly appreciated.

Admittedly I am new to C++ so some concepts may have alluded me and I have tried searching for a solution.

Anyway first, here's the code that works for me.

#include <EEPROM.h>

int serial_putc( char c, FILE * ) 
{
  Serial.write( c );

  return c;
} 

void printf_begin(void)
{
  fdevopen( &serial_putc, 0 );
}

struct config_t
{
        // Server stuff
        char        authkey[40];
        bool        dhcp_enabled;
        byte        ip[4];
        byte        gw_ip[4];
        byte        dns_ip[4];

        // Wesbite notify stuff
        char        wn_host[100];
        char        wn_path[100];
        uint16_t    wn_port;

        //xmbc stuff
        char        xmbc_website[50] ;
        char        xmbc_path[50];
        uint16_t    xmbc_port;
        byte        validConfig;       
};

config_t * config;
  
void readConfigParam(char * buffer, const char * param, byte len)
{
    for (byte i = 0; i < len; i++)
      *buffer++ = (char) EEPROM.read( (uint16_t) param++);
}

void writeConfigParam(char * input, const char * param, byte len)
{
    for (byte i = 0; i < len; i++)
        EEPROM.write( (uint16_t ) param++,(const byte) *input++);
}

void testConfigWrite()
{
    writeConfigParam("www.myexample.com"
                        , config->wn_host
                        , sizeof config->wn_host 
                     );
                     
    writeConfigParam("shivermeauthy"
                        , config->authkey
                        , sizeof config->authkey
                    );
}

void testConfigRead()
{
    char webhost[ sizeof config->wn_host ];
    char authKey[ sizeof config->authkey ];

    readConfigParam( webhost, config->wn_host, sizeof config->wn_host );
    readConfigParam( authKey, config->authkey, sizeof config->authkey );

    printf_P( PSTR("Web Host: %s\nAuthorise key: %s\n")
          ,webhost
          ,authKey
        );
}

void setup() {

  Serial.begin(115200);
  printf_begin();
  
  // Set config pointer to EEPROM location 0
  config = 0;
  
  // Run tests
  testConfigWrite();
  testConfigRead();
}

void loop() {

}

Now here is where I am struggling to get my mind around these compiler errors and what I am doing wrong.

#include <EEPROM.h>

int serial_putc( char c, FILE * ) 
{
  Serial.write( c );

  return c;
} 

void printf_begin(void)
{
  fdevopen( &serial_putc, 0 );
}

struct config_t
{
        struct server_t
        {
          char        authkey[40];
          bool        dhcp_enabled;
          byte        ip[4];
          byte        gw_ip[4];
          byte        dns_ip[4];

        } server;

        struct webNotify_t
        {
          char        host[100];
          char        path[100];
          uint16_t    port;

        } web;

        //xmbc stuff
        char        xmbc_website[50] ;
        char        xmbc_path[50];
        uint16_t    xmbc_port;
        byte        validConfig;       
};

config_t * config;
       
void readConfigParam(char * buffer, const char * param, byte len)
{
    for (byte i = 0; i < len; i++)
      *buffer++ = (char) EEPROM.read( (uint16_t) param++);
}

void writeConfigParam(char * input, const char * param, byte len)
{
    for (byte i = 0; i < len; i++)
        EEPROM.write( (uint16_t ) param++,(const byte) *input++);
}

void testConfigWrite()
{
    writeConfigParam("www.myexample.com"
                        , config->web->host
                        , sizeof config->web->host 
                     );
                     
    writeConfigParam("shivermeauthy"
                        , config->server->authkey
                        , sizeof config->server->authkey
                    );
}

void testConfigRead()
{
    char webhost[ sizeof config->web->host ];
    char authKey[ sizeof config->server->authkey ];

    readConfigParam( webhost, config->web->host, sizeof config->web->host );
    readConfigParam( authKey, config->server->authkey, sizeof config->server->authkey );

    printf_P( PSTR("Web Host: %s\nAuthorise key: %s\n")
          ,webhost
          ,authKey
        );
}

void setup() {

  Serial.begin(115200);
  printf_begin();
  
  // Set config pointer to EEPROM location 0
  config = 0;
  
  // Run tests
  testConfigWrite();
  testConfigRead();
}

void loop() {

}

The compile errors I get are as follows:-

Arduino: 1.5.7 (Windows 7), Board: "Arduino Uno"

Using library EEPROM in folder: C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\EEPROM (legacy)



C:\Program Files (x86)\Arduino/hardware/tools/avr/bin/avr-g++ -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -MMD -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=157 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR -IC:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino -IC:\Program Files (x86)\Arduino\hardware\arduino\avr\variants\standard -IC:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\EEPROM C:\Users\Del\AppData\Local\Temp\build3074773576706612058.tmp\sketch_dec18a.cpp -o C:\Users\Del\AppData\Local\Temp\build3074773576706612058.tmp\sketch_dec18a.cpp.o 

sketch_dec18a.ino: In function 'void testConfigWrite()':
sketch_dec18a.ino:62:38: error: base operand of '->' has non-pointer type 'config_t::webNotify_t'
sketch_dec18a.ino:63:45: error: base operand of '->' has non-pointer type 'config_t::webNotify_t'
sketch_dec18a.ino:67:41: error: base operand of '->' has non-pointer type 'config_t::server_t'
sketch_dec18a.ino:68:48: error: base operand of '->' has non-pointer type 'config_t::server_t'
sketch_dec18a.ino: In function 'void testConfigRead()':
sketch_dec18a.ino:73:37: error: base operand of '->' has non-pointer type 'config_t::webNotify_t'
sketch_dec18a.ino:74:40: error: base operand of '->' has non-pointer type 'config_t::server_t'
sketch_dec18a.ino:76:22: error: 'webhost' was not declared in this scope
sketch_dec18a.ino:76:42: error: base operand of '->' has non-pointer type 'config_t::webNotify_t'
sketch_dec18a.ino:76:68: error: base operand of '->' has non-pointer type 'config_t::webNotify_t'
sketch_dec18a.ino:77:22: error: 'authKey' was not declared in this scope
sketch_dec18a.ino:77:45: error: base operand of '->' has non-pointer type 'config_t::server_t'
sketch_dec18a.ino:77:77: error: base operand of '->' has non-pointer type 'config_t::server_t'

Once again, any guidance on my foolishness or otherwise would be appreciated.

Thanks for reading.

I think the second nested structure is not a pointer
config->web->host
and should be
config->web.host
at first sight.

Budvar10:
I think the second nested structure is not a pointer
config->web->host
and should be
config->web.host
at first sight.

Not just that one. This same problem is riddled right through the code.

Just assume that everywhere you've used -> after web it should be a dot.

Yes KenF. I supposed that it is clear. :grin:

Budvar10:
I think the second nested structure is not a pointer
config->web->host
and should be
config->web.host
at first sight.

First of all thank you for your reply.

Budvar10:

I have tried it both as config->web->host and config->web.host neither compiled.

KenF:
Not just that one. This same problem is riddled right through the code.

Just assume that everywhere you've used -> after web it should be a dot.

Thanks Kenf, I understand when using a pointer to struct your should use -> for it's members, and it's my fault for not explaining what else I had already tried. I am still unsure however how to get the result I desire, if it is possible. Writing to EEPROM using struct within struct pointers.

I am new to posting on forums as well as the Arduino and C worlds, please forgive me. I am trying to learn fast. Thanks for your time.

You need to do the same with config->server->authkey

In fact, anywhere you have config ->something ->something, you need to change the second -> to a dot

Having done a quick swoop through to make those changes, I find this now compiles.

#include <EEPROM.h>

int serial_putc( char c, FILE * ) 
{
  Serial.write( c );

  return c;
} 

void printf_begin(void)
{
  fdevopen( &serial_putc, 0 );
}

struct config_t
{
        struct server_t
        {
          char        authkey[40];
          bool        dhcp_enabled;
          byte        ip[4];
          byte        gw_ip[4];
          byte        dns_ip[4];

        } server;

        struct webNotify_t
        {
          char        host[100];
          char        path[100];
          uint16_t    port;

        } web;

        //xmbc stuff
        char        xmbc_website[50] ;
        char        xmbc_path[50];
        uint16_t    xmbc_port;
        byte        validConfig;       
};

config_t * config;
       
void readConfigParam(char * buffer, const char * param, byte len)
{
    for (byte i = 0; i < len; i++)
      *buffer++ = (char) EEPROM.read( (uint16_t) param++);
}

void writeConfigParam(char * input, const char * param, byte len)
{
    for (byte i = 0; i < len; i++)
        EEPROM.write( (uint16_t ) param++,(const byte) *input++);
}

void testConfigWrite()
{
    writeConfigParam("www.myexample.com"
                        , config->web.host
                        , sizeof config->web.host 
                     );
                     
    writeConfigParam("shivermeauthy"
                        , config->server.authkey
                        , sizeof config->server.authkey
                    );
}

void testConfigRead()
{
    char webhost[ sizeof config->web.host ];
    char authKey[ sizeof config->server.authkey ];

    readConfigParam( webhost, config->web.host, sizeof config->web.host );
    readConfigParam( authKey, config->server.authkey, sizeof config->server.authkey );

    printf_P( PSTR("Web Host: %s\nAuthorise key: %s\n")
          ,webhost
          ,authKey
        );
}

void setup() {

  Serial.begin(115200);
  printf_begin();
  
  // Set config pointer to EEPROM location 0
  config = 0;
  
  // Run tests
  testConfigWrite();
  testConfigRead();
}

void loop() {

}

web is not a pointer. It is a field in your config struct.

The components of web are accessed with the dot syntax not the pointer syntax.

So the config->web.host syntax should be correct.

If you tried that, and it didn't work, then you had something else wrong.

The other problem, it seems to me, is you never create an actual instance of your config struct.

You define a pointer variable which is a pointer to such a struct, but you never declare an instance of the struct either statically or dynamically. Unless that is being done somewhere else.

KenF:
You need to do the same with config->server->authkey

In fact, anywhere you have config ->something ->something, you need to change the second -> to a dot

Having done a quick swoop through to make those changes, I find this now compiles.

#include <EEPROM.h>

int serial_putc( char c, FILE * )
{
  Serial.write( c );

return c;
}

void printf_begin(void)
{
  fdevopen( &serial_putc, 0 );
}

struct config_t
{
        struct server_t
        {
          char        authkey[40];
          bool        dhcp_enabled;
          byte        ip[4];
          byte        gw_ip[4];
          byte        dns_ip[4];

} server;

struct webNotify_t
        {
          char        host[100];
          char        path[100];
          uint16_t    port;

} web;

//xmbc stuff
        char        xmbc_website[50] ;
        char        xmbc_path[50];
        uint16_t    xmbc_port;
        byte        validConfig;     
};

config_t * config;
     
void readConfigParam(char * buffer, const char * param, byte len)
{
    for (byte i = 0; i < len; i++)
      *buffer++ = (char) EEPROM.read( (uint16_t) param++);
}

void writeConfigParam(char * input, const char * param, byte len)
{
    for (byte i = 0; i < len; i++)
        EEPROM.write( (uint16_t ) param++,(const byte) *input++);
}

void testConfigWrite()
{
    writeConfigParam("www.myexample.com"
                        , config->web.host
                        , sizeof config->web.host
                    );
                   
    writeConfigParam("shivermeauthy"
                        , config->server.authkey
                        , sizeof config->server.authkey
                    );
}

void testConfigRead()
{
    char webhost[ sizeof config->web.host ];
    char authKey[ sizeof config->server.authkey ];

readConfigParam( webhost, config->web.host, sizeof config->web.host );
    readConfigParam( authKey, config->server.authkey, sizeof config->server.authkey );

printf_P( PSTR("Web Host: %s\nAuthorise key: %s\n")
          ,webhost
          ,authKey
        );
}

void setup() {

Serial.begin(115200);
  printf_begin();
 
  // Set config pointer to EEPROM location 0
  config = 0;
 
  // Run tests
  testConfigWrite();
  testConfigRead();
}

void loop() {

}

Thank you KenF, I will try that.

michinyon:
web is not a pointer. It is a field in your config struct.

The components of web are accessed with the dot syntax not the pointer syntax.

So the config->web.host syntax should be correct.

If you tried that, and it didn't work, then you had something else wrong.

The other problem, it seems to me, is you never create an actual instance of your config struct.

You define a pointer variable which is a pointer to such a struct, but you never declare an instance of the struct either statically or dynamically. Unless that is being done somewhere else.

Thanks michinyon,

My approach, which I hope to get guidance on if it is wrong, is declaring only the pointer to config for positional address use. The code that I posted working, appears to handle this well from my testing so far. I am using the struct pointer(s) only to handle addresses for the variables in EEPROM. I aimed to use inner struct pointers to easily retrieve grouped data and make changes to it via html forms or otherwise, without having to bring the whole config structure into RAM at one time. Perhaps my thinking is wrong?

KenF:
You need to do the same with config->server->authkey

In fact, anywhere you have config ->something ->something, you need to change the second -> to a dot

Having done a quick swoop through to make those changes, I find this now compiles.

#include <EEPROM.h>

int serial_putc( char c, FILE * )
{
  Serial.write( c );

return c;
}

void printf_begin(void)
{
  fdevopen( &serial_putc, 0 );
}

struct config_t
{
        struct server_t
        {
          char        authkey[40];
          bool        dhcp_enabled;
          byte        ip[4];
          byte        gw_ip[4];
          byte        dns_ip[4];

} server;

struct webNotify_t
        {
          char        host[100];
          char        path[100];
          uint16_t    port;

} web;

//xmbc stuff
        char        xmbc_website[50] ;
        char        xmbc_path[50];
        uint16_t    xmbc_port;
        byte        validConfig;     
};

config_t * config;
     
void readConfigParam(char * buffer, const char * param, byte len)
{
    for (byte i = 0; i < len; i++)
      *buffer++ = (char) EEPROM.read( (uint16_t) param++);
}

void writeConfigParam(char * input, const char * param, byte len)
{
    for (byte i = 0; i < len; i++)
        EEPROM.write( (uint16_t ) param++,(const byte) *input++);
}

void testConfigWrite()
{
    writeConfigParam("www.myexample.com"
                        , config->web.host
                        , sizeof config->web.host
                    );
                   
    writeConfigParam("shivermeauthy"
                        , config->server.authkey
                        , sizeof config->server.authkey
                    );
}

void testConfigRead()
{
    char webhost[ sizeof config->web.host ];
    char authKey[ sizeof config->server.authkey ];

readConfigParam( webhost, config->web.host, sizeof config->web.host );
    readConfigParam( authKey, config->server.authkey, sizeof config->server.authkey );

printf_P( PSTR("Web Host: %s\nAuthorise key: %s\n")
          ,webhost
          ,authKey
        );
}

void setup() {

Serial.begin(115200);
  printf_begin();
 
  // Set config pointer to EEPROM location 0
  config = 0;
 
  // Run tests
  testConfigWrite();
  testConfigRead();
}

void loop() {

}

Thank you KenF, perhaps it was yet another one of those days for me, because you have written it exactly as I thought I had originally, before coming up with problems and ending up trying various methods and becoming irrational and probably causing more problems in the code. This compiles and works. I am not worthy. Thanks again.