Random chars and 0's reading struct in EEPROM

Hello world

I'm trying to write and read data structs in EEPROM. This is an auxiliary sketch to test the data structs and their behaviour in EEPROM so it can be applied in a web client project.

I'm using Arduino Duemilanove ATmega328 in Arduino IDE in Windows 10.

What I do is basically define a struct Arduino with some fixed parameters, write them using EEPROM.put and then I try to read them using EEPROM.get inside a function I defined. The whole code is here:

#include <EEPROM.h>

byte MAC[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte IP[] = {  192, 168, 1, 228};
byte Gateway[] = {  192, 168, 1, 254};
byte DNS[] = {  192, 168, 1, 254};
byte Subnet[] = { 255,255,255,0 }; 
char arduinoName = "test_arduino";
byte serverIP[] = { 192, 168, 1, 218 }; 
int ServerPort = 8080;    
int Bus = 2;
int period = 10000;
int headerSize = 105;
int MaxSize = 1000;

struct Arduino {
  char Name[20];
  int sendPeriod;
  int respHeaderSize;
  int serverPort;
  byte serverName[4];
  byte mac[6];
  byte ip[4];
  byte subnet[4];
  byte gateway[4];
  byte dns[4];
  int respMaxSize;
  int OneWireBus;
};

Arduino arduino = {
  arduinoName,
  period,
  headerSize,
  ServerPort,
  serverIP,
  MAC,
  IP,
  Subnet,
  Gateway,
  DNS,
  MaxSize,
  Bus
};

void setup(){
  int eeAddress = 1;
  Serial.begin(9600);
  EEPROM.put(eeAddress, arduino);
  Serial.println(arduino.sendPeriod);
  Serial.print("SUCCESS\n");
  readArduinoinEEPROM();
}

void loop(){ /* Empty loop */ }

Arduino readArduinoinEEPROM() {
  Arduino arduino;
  EEPROM.get(1, arduino);
  Serial.println(":::ARDUINO FIXED PARAMETERS:::");
  Serial.println();
  Serial.println("Name: " + String(arduino.Name));
  Serial.print("IP: ");
  printIPAddress(arduino.ip);
  Serial.print("MAC: ");
  printMACAddress(arduino.mac);
  Serial.println("One wire bus (DS18B20): " + String(arduino.OneWireBus));
  Serial.print("DNS: ");
  printIPAddress(arduino.dns);
  Serial.print("Subnet: ");
  printIPAddress(arduino.subnet);
  Serial.print("Gateway: ");
  printIPAddress(arduino.gateway);
  Serial.print("Server IP: ");
  printIPAddress(arduino.serverName);
  Serial.println("Server port: " + String(arduino.serverPort));
  Serial.println("Send cycle period: " + String(arduino.sendPeriod));
  Serial.println("Server response header size (chars): " + String(arduino.respHeaderSize));
  Serial.println("Server response max size (chars): " + String(arduino.respMaxSize));
  Serial.println();
  return arduino;
}

void printIPAddress(byte IP[]) {
  for (byte thisByte = 0; thisByte < 4; thisByte++) {
    if (thisByte == 3) {
      Serial.println(IP[thisByte], DEC);
    }
    Serial.print(IP[thisByte], DEC);
    Serial.print(".");
  }
}

void printMACAddress(byte MAC[]) {
  for (byte thisByte = 0; thisByte < 4; thisByte++) {
    if (thisByte == 3) {
      Serial.println(MAC[thisByte], HEX);
    }
    Serial.print(MAC[thisByte], HEX);
    Serial.print(".");
  }
}

What I get in the Serial Monitor is:

0
SUCCESS
:::ARDUINO FIXED PARAMETERS:::

Name: 7i⸮
IP: 0.0.0.0
0.MAC: 0.0.0.0
0.One wire bus (DS18B20): 0
DNS: 0.0.0.0
0.Subnet: 0.0.0.0
0.Gateway: 0.0.0.0
0.Server IP: 0.0.0.0
0.Server port: 0
Send cycle period: 0
Server response header size (chars): 0
Server response max size (chars): 0

This doesn't add up. Why?

Thanks for your attention

Best regards,
arocha17

In this line:

char arduinoName = "test_arduino";

A string doesn't fit in a char.

Fix it to:

char arduinoName[] = "test_arduino";

Still get the same output with you suggestion.

Then I changed to:

char arduinoName[] = "test_arduino\0";

And still got the same result...

Actually, if you increase the "Compile Warnings" to "All" in "Preferences", you get the following warnings:

warning: invalid conversion from 'char*' to 'char' [-fpermissive]
warning: narrowing conversion of 'period' from 'int' to 'char' inside { } [-Wnarrowing]
warning: narrowing conversion of 'headerSize' from 'int' to 'char' inside { } [-Wnarrowing]
warning: narrowing conversion of 'ServerPort' from 'int' to 'char' inside { } [-Wnarrowing]
warning: invalid conversion from 'byte* {aka unsigned char*}' to 'char' [-fpermissive]
warning: invalid conversion from 'byte* {aka unsigned char*}' to 'char' [-fpermissive]
warning: invalid conversion from 'byte* {aka unsigned char*}' to 'char' [-fpermissive]
warning: invalid conversion from 'byte* {aka unsigned char*}' to 'char' [-fpermissive]
warning: invalid conversion from 'byte* {aka unsigned char*}' to 'char' [-fpermissive]
warning: invalid conversion from 'byte* {aka unsigned char*}' to 'char' [-fpermissive]
warning: narrowing conversion of 'MaxSize' from 'int' to 'char' inside { } [-Wnarrowing]
warning: narrowing conversion of 'Bus' from 'int' to 'char' inside { } [-Wnarrowing]
warning: missing initializer for member 'Arduino::sendPeriod' [-Wmissing-field-initializers]
warning: missing initializer for member 'Arduino::respHeaderSize' [-Wmissing-field-initializers]
warning: missing initializer for member 'Arduino::serverPort' [-Wmissing-field-initializers]
warning: missing initializer for member 'Arduino::serverName' [-Wmissing-field-initializers]
warning: missing initializer for member 'Arduino::mac' [-Wmissing-field-initializers]
warning: missing initializer for member 'Arduino::ip' [-Wmissing-field-initializers]
warning: missing initializer for member 'Arduino::subnet' [-Wmissing-field-initializers]
warning: missing initializer for member 'Arduino::gateway' [-Wmissing-field-initializers]
warning: missing initializer for member 'Arduino::dns' [-Wmissing-field-initializers]
warning: missing initializer for member 'Arduino::respMaxSize' [-Wmissing-field-initializers]
warning: missing initializer for member 'Arduino::OneWireBus' [-Wmissing-field-initializers]

Because you can't iniatialize an array data member in a struct like this:

Arduino arduino = {
  arduinoName, <-- Can't to this
  period,
  headerSize,
  ServerPort,
  serverIP, <-- Can't to this
  MAC, <-- Can't to this
  IP, <-- Can't to this
  Subnet, <-- Can't to this
  Gateway, <-- Can't to this
  DNS, <-- Can't to this
  MaxSize,
  Bus
};

Why? Your struct expects 20 chars in the first data member, so the first 12 initializers you use will go to the "char Name[20];" data member.

But you can do this, inline:

Arduino arduino = {
  "test_arduino",
  10000,
  105,
  8080,
  { 192, 168, 1, 218 },
  { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED },
  {  192, 168, 1, 228},
  { 255,255,255,0 },
  {  192, 168, 1, 254},
  {  192, 168, 1, 254},
  1000,
  2
};

It saves memory, as you don't need these variables anymore:

byte MAC[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte IP[] = {  192, 168, 1, 228};
byte Gateway[] = {  192, 168, 1, 254};
byte DNS[] = {  192, 168, 1, 254};
byte Subnet[] = { 255,255,255,0 };
char arduinoName[] = "test_arduino";
byte serverIP[] = { 192, 168, 1, 218 };
int ServerPort = 8080;    
int Bus = 2;
int period = 10000;
int headerSize = 105;
int MaxSize = 1000;

Note:
You don't need to initialize it like this:

char arduinoName[] = "test_arduino\0";

You can just use it without '\0', because the compiler already place it in the end of your char array as it is a string.

Thank you! It worked perfectly and I understood what you meant.

After testing the code the way you said, I changed it to:

String arduinoName = "TEST_ARDUINO"";

struct Arduino {
  String Name;
  int sendPeriod;
  int respHeaderSize;
  int serverPort;
  byte serverName[4];
  byte mac[6];
  byte ip[4];
  byte subnet[4];
  byte gateway[4];
  byte dns[4];
  int respMaxSize;
  int OneWireBus;
};

Arduino arduino = {
  arduinoName,
  10000,
  105,
  8080,
  { 192, 168, 1, 218 },
  { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED },
  {  192, 168, 1, 228},
  { 255,255,255,0 },
  {  192, 168, 1, 254},
  {  192, 168, 1, 254},
  1000,
  2
};

And it worked (it saved the new capitalized string).

I'm assuming it is because of the way the String object is built. If you could clarify this to me it would be great.

Thank you again to both of you.

Best regards,
arocha17

arocha17:
And it worked (it saved the new capitalized string).

I'm assuming it is because of the way the String object is built. If you could clarify this to me it would be great.

Both assumptions are wrong (it saved a pointer to memory that happens to have the desired content).

Don't use String in this context (and best don't use Strings at all).

String arduinoName = "TEST_ARDUINO"";

struct Arduino {
  String Name;
  int sendPeriod;
  int respHeaderSize;
  int serverPort;
  byte serverName[4];
  byte mac[6];
  byte ip[4];
  byte subnet[4];
  byte gateway[4];
  byte dns[4];
  int respMaxSize;
  int OneWireBus;
};

Arduino arduino = {
  arduinoName,
  10000,
  105,
  8080,
  { 192, 168, 1, 218 },
  { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED },
  {  192, 168, 1, 228},
  { 255,255,255,0 },
  {  192, 168, 1, 254},
  {  192, 168, 1, 254},
  1000,
  2
};

Why use a separated variable arduinoName?
You can access the name using the the data member Name from Arduino struct.

Don't use String in this context (and best don't use Strings at all).

Don't use String, use string (null terminated char array).

Rather than this:

struct Arduino {
  char Name[20];
  int sendPeriod;
  int respHeaderSize;
  int serverPort;
  byte serverName[4];
  byte mac[6];
  byte ip[4];
  byte subnet[4];
  byte gateway[4];
  byte dns[4];
  int respMaxSize;
  int OneWireBus;
};

Arduino arduino = {
  "TEST_ARDUINO",
  10000,
  105,
  8080,
  { 192, 168, 1, 218 },
  { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED },
  {  192, 168, 1, 228},
  { 255,255,255,0 },
  {  192, 168, 1, 254},
  {  192, 168, 1, 254},
  1000,
  2
};

You can use this:

struct Arduino {
  char Name[20] = "TEST_ARDUINO";
  int sendPeriod = 10000;
  int respHeaderSize = 105;
  int serverPort = 8080;
  byte serverName[4] = { 192, 168, 1, 218 };
  byte mac[6] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
  byte ip[4] = {  192, 168, 1, 228};
  byte subnet[4] = { 255,255,255,0 };
  byte gateway[4] =  { 192, 168, 1, 254};
  byte dns[4] = { 192, 168, 1, 254};
  int respMaxSize = 1000;
  int OneWireBus = 2;
};

Arduino arduino;

With this, you can easily reset the arduino variable using:

arduino = Arduino();