Help understanding how to optimize this simple code and unexepcted behaviour

Hi all,
I've been coding arduino for about a year. It is not for work, just a passion. Today I've decided that it was time to start using EEPROM memory. So I wrote this simple code. Basically you can input a command via serial, arduino process it. Commands are write, read, erase, read_all, erase_all. I'm posting it here because I got an unexpected behaviour: when I type WRITE then IP (write for 15 chars starting from 0) it writes also the 1024 EEPROM slot.

I'd like also to receive advices to improve it.
Thank you.

PS: I tried to comment it so you can understand it better.

#include <EEPROM.h>

#define ALLOCATED_BUFFER 20

void serial_read() {
  if (Serial.available()) {
    static int length = 0;
    static char buffer[ALLOCATED_BUFFER];
    static int type = 0;
    static int info = 0;
    char r = Serial.read();
    if (r == '\r' ) {                                                     //only cares bout \r    end of line, handle!
      if (type == 0) {
        Serial.print(F("Command: "));
        Serial.println(buffer);
      } else if (info == 0) {
        Serial.print(F("Data: "));
        Serial.println(buffer);
      } else {
        Serial.println(buffer);
      }
      if (strstr(buffer,"DATES")) {                                       //List
        Serial.println(F("************************************\n"));
        Serial.println(F("IP            <===>     max 15 char"));
        Serial.println(F("NAME          <===>     max 15 char"));
        Serial.println(F("\n***************END**************************"));
      }else if (strstr(buffer, "HELP")) {                    // List commands
        Serial.println(F("********************************************\n"));
        Serial.println(F("DATES         <===>     List available dates"));
        Serial.println(F("ERASE         <===>     Delete that date"));
        Serial.println(F("ERASE_ALL     <===>     Delete all memory"));
        Serial.println(F("READ          <===>     Read that date"));
        Serial.println(F("READ_ALL      <===>     Read all memory"));
        Serial.println(F("WRITE         <===>     Write that date"));
        Serial.println(F("\n***************END**************************"));
      } else if (strstr(buffer, "ERASE_ALL")) {                   // Erase all memory
        eeprom_erase_all();
      } else if (strstr(buffer, "READ_ALL")) {                    // Read all
        eeprom_read_all();
      }  else if(strstr(buffer, "WRITE")) {                                //  Write info
        type = 1;
        Serial.println(F("What do you want to write?"));
      } else if (strstr(buffer, "READ")) {                          // Read info
        type = 2;
        Serial.println(F("What do you want to read?"));
      } else if (strstr(buffer, "ERASE")) {                        // Erase info
        type = 3;
        Serial.println(F("What do you want to erase?"));
      } else if (type != 0) {                                      // get info
        if (info == 0) {
          if (strstr(buffer, "IP")) {                                 // 1 = IP
            switch (type) {
              case 1:
                Serial.println(F("Type data"));
                info = 1;
                break;
              case 2:
                Serial.println(eeprom_reader(1));
                type = 0;
                info = 0;
                break;
              case 3:
                eeprom_erase(1);
                Serial.println(F("Erased successfully"));
                type = 0;
                info = 0;
              default:
                break;
            }
          } else if (strstr(buffer, "NAME")) {                       // 2 = NAME
            switch (type) {
              case 1:
                Serial.println(F("Type data"));
                info = 2;
                break;
              case 2:
                Serial.println(eeprom_reader(2));
                type = 0;
                info = 0;
                break;
              case 3:
                eeprom_erase(2);
                Serial.println(F("Erased successfully"));
                type = 0;
                info = 0;
              default:
                break;
            }
            }else {
            Serial.println(F("Not valid data, abort"));
            type = 0;
            info = 0;
          }
        } else {
          eeprom_writer(info, buffer);
          Serial.println(F("Written successfully"));
          type = 0;
          info = 0;
        }

      } else {
        Serial.println(F("Not a valid command"));
        type = 0;
        info = 0;
      }


      length = 0;
    } else if (r == '\n') {                       //don't care about \n
      return;                                                                    
    } else if (length < ALLOCATED_BUFFER) {
      buffer[length] = r;
      length++;
      buffer[length] = 0;
    }
  }
}

int data_length_ (int info) {
  switch (info) {
    case 1:           //IP
      return 15;
    case 2:
      return 15;       // NAME
    default:
      return 0;
  }
}

int data_init_ (int info) {
  switch (info) {
    case 1:           //IP
      return 0;
    case 2:         //NAME
      return 15;
    default:
      return 0;
  }
}

char* eeprom_reader(int info) {
  int data_init = data_init_(info);
  int data_length = data_length_(info);
  char* buf = (char *) malloc (ALLOCATED_BUFFER);
  char buffer[ALLOCATED_BUFFER];
  buffer[0] = '\0';
  if (data_length != 0) {
    // time to read
    for (int x = 0; x < data_length; x++) {
      //read each character and add to buffer
      char ch = EEPROM.read(x + data_init);
      buffer[x] = ch;
      buffer[x + 1] = '\0';
    }
  }
  //read complete :)
  strcpy (buf, buffer);
  return buf;
}

void eeprom_writer(int info, char text[ALLOCATED_BUFFER]) {
  int data_init = data_init_(info);
  int data_length = data_length_(info);
  for (int x = 0; x < data_length; x++) {
    //write each character
    EEPROM.update((x + data_init), text[x]);
  }
}

void eeprom_erase(int info) {
  int data_init = data_init_(info);
  int data_length = data_length_(info);
  for (int x = 0; x < data_length; x++) {
    //write each null
    EEPROM.update((x + data_init), '\0');
  }
}

void eeprom_erase_all() {
  for (int x = 0; x < 1025; x++) {
    //write each null
    EEPROM.update((x), '\0');
  }
  Serial.println("Deleted all memory");
}

void eeprom_read_all () {
  for (int x = 0; x < 1025; x++) {
    //read each
    Serial.print(F("#"));
    Serial.print(x);
    Serial.print(F("="));
    Serial.println((char)EEPROM.read(x));
  }
}


void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  Serial.println(F("Ready! :)"));
  Serial.println(F("Type HELP for help"));
}

void loop() {
  // put your main code here, to run repeatedly:
  if (Serial.available()) {
    serial_read();
  }
}
  for (int x = 0; x < 1025; x++) {
    EEPROM.update((x), '\0');

what type of arduino do you have ? there are only 1024 bytes on the ATmega328P (UNO) so there is no address 1024. It goes from 0 to 1023.

you should not malloc() your buffers (which you fail to free later so you are leaking memory badly) just use static buffers

I suggest that you break your serial_read() function into at least two parts. First of all just collect the incoming characters and save them. Second, parse the saved info and act on it. It will make things a lot less confusing.

It looks as if, for some commands, you intend to ask the user for more data. I think you should deal with that separately. Writing effective user-input code is not trivial because users often make mistakes and they must be allowed for.

Maybe have a look at Serial Input Basics - simple reliable non-blocking ways to receive data. And at the user-input example in Planning and Implementing a Program

...R

J-M-L:
there are only 1024 bytes on the ATmega328P (UNO) so there is no address 1024. It goes from 0 to 1023.

you're right :wink: thank you

J-M-L:
you should not malloc() your buffers (which you fail to free later so you are leaking memory badly) just use static buffers

ok.

Robin2:
I suggest that you break your serial_read() function into at least two parts. First of all just collect the incoming characters and save them. Second, parse the saved info and act on it. It will make things a lot less confusing.

It looks as if, for some commands, you intend to ask the user for more data. I think you should deal with that separately. Writing effective user-input code is not trivial because users often make mistakes and they must be allowed for.

Maybe have a look at Serial Input Basics - simple reliable non-blocking ways to receive data. And at the user-input example in Planning and Implementing a Program

...R

thank you, I will read those posts.