Out of memory issue

Hi everyone,

I’m working on a project with a GSM shield and it seems that Arduino is running out of memory when I want to open a message on the shield (AT+CMGR command)

I explain:
I send a message to the shield, the arduino checks every 10s if a message has been received and if yes, open it. Another function (see below, thats GetMsg() function) gets the message. Because my circuit is already done, I can’t send information on serial, so I send back what GetMsg() to my phone. I always received the same message (only the date change):

AT+CMGR=1
+CMGR: “REC UNREAD”, “phone_number”, “” ", 18/09/23,1
So, as you can see, the message is cut, and I can’t see the content of the message.

I already have this problem before and solved it by deleting some strings in the program, but now, its doesn’t work anymore. When I compile, it tells that I used 52% for global variable, so about 1000 bytes is available for local variable. I used lots of strings and functions that return strings in my program; maybe that the problem, but I need them.

I tried to see the free memory during execution and it’s about 600 bytes.

I think it should be a memory issue but don’t understand where the problem is. Someone has any idea ?

Function to get message frome the gsm shield (found on Internet)

String GetMsg()
{
  String inTxt = "";
  char Car;
  while (mySerial.available())
  {
    Car = mySerial.read();
    inTxt = inTxt+Car;
  }
  return inTxt;  
}

Function to check if a message has been received

void check_SMS(){

    msg = "";
    msg = GetMsg();
    delay(500);
    if (msg.indexOf("+CMTI:")>-1)
    {
      char numSMS = msg.substring(msg.indexOf(",")+1).toInt();
    
      mySerial.print("AT+CMGR=");
      mySerial.println(numSMS, DEC);
      delay(1000);
      msg = GetMsg();
      delay(500);
      if (numSMS >= 25)
      {
        mySerial.print("AT+CMGD=");
        mySerial.println("1,4");
        delay(2000);
      }
      String send_num = msg.substring(msg.indexOf(",")+1, msg.indexOf(",")+15);
      //Serial.println(send_num);
      if (send_num.equals(strcpy_P(buffer, (char*)pgm_read_word(&(num_table[0])))) || send_num.equals(strcpy_P(buffer, (char*)pgm_read_word(&(num_table[1])))))
      {
        state_msg(msg, send_num);
      }

Function that do something based on the content of the message

void state_msg(String msg_received, String send_num)
{

    //Clear only line 1
    lcdClearLine(1);
    lcd.print("Mem Et:");
    lcd.setCursor(8, 1);
    lcd.print(freeMemory());
    delay(2000);
  
  if (msg_received.indexOf("rst")>-1) resetFunc();

  else
    {
      //Send back received message
      send_SMS(msg_received, strcpy_P(buffer, (char*)pgm_read_word(&(num_table[0]))));
      delay(4000);
    }
}

Thanks :slight_smile:

Do not post partial code, the problem is rarely located in the snippets. You are using the "String" class and this is most likely your problem, so remove it and use cstrings (char arrays) instead.

How do you KNOW when a complete message has been received? There is nothing in your snippets that indicates that "a complete message" is anything other than "everything that is in the buffer at this moment".

Well, obviously, "everything that is in the buffer at this moment" is NOT "a complete message".

String GetMsg()
{
  const byte buffLimit = 80;
  static char buff[buffLimit + 1]; // Allow for null terminator
  static byte buffIndex = 0;
  static String returnBuffer = "";


  char c;
  returnBuffer = "";  // Default return value
  while (mySerial.available())
  {
    c = mySerial.read();
    
    // Look for line terminator (Return or Newline)
    if (c == '\r' || c == '\n')
    {
      buff[buffIndex] = '\0'; // Null Terminator
      returnBuffer = buff;
      buffIndex = 0;  // Prepare for next line
      break;  // Exit the while() and return the value
    }
    if (buffIndex < buffLimit)
      buff[buffIndex++] = c;
  }
  
  return returnBuffer;
}

johnwasser:

String GetMsg()

{
  const byte buffLimit = 80;
  static char buff[buffLimit + 1]; // Allow for null terminator
  static byte buffIndex = 0;
  static String returnBuffer = “”;

char c;
  returnBuffer = “”;  // Default return value
  while (mySerial.available())
  {
    c = mySerial.read();
   
    // Look for line terminator (Return or Newline)
    if (c == ‘\r’ || c == ‘\n’)
    {
      buff[buffIndex] = ‘\0’; // Null Terminator
      returnBuffer = buff;
      buffIndex = 0;  // Prepare for next line
      break;  // Exit the while() and return the value
    }
    if (buffIndex < buffLimit)
      buff[buffIndex++] = c;
  }
 
  return returnBuffer;
}

There is NO excuse for wrapping the char array in a String instance. Just return a pointer to the char array.

johnwasser:

String GetMsg()

{
  const byte buffLimit = 80;
  static char buff[buffLimit + 1]; // Allow for null terminator
  static byte buffIndex = 0;
  static String returnBuffer = “”;

char c;
  returnBuffer = “”;  // Default return value
  while (mySerial.available())
  {
    c = mySerial.read();
   
    // Look for line terminator (Return or Newline)
    if (c == ‘\r’ || c == ‘\n’)
    {
      buff[buffIndex] = ‘\0’; // Null Terminator
      returnBuffer = buff;
      buffIndex = 0;  // Prepare for next line
      break;  // Exit the while() and return the value
    }
    if (buffIndex < buffLimit)
      buff[buffIndex++] = c;
  }
 
  return returnBuffer;
}

Your code will break if a line exceeds 79 characters.
And it returns an empty string if it finishes reading few data but couldn’t find the line feed.

Thanks you all for your replies.
So, as I understand, I should use a pointer instead of a string for my function GetMsg(). In fact, I often tried to avoid pointers even if it a really good thing. I always have problem to understand when and how I can use them. And please, don't say me that a pointer contains an address, even if it's right. I already know that :slight_smile: I think I will show this to a friend first and come back to avoid you to explain basic programming things to me.

@Danois90:

Danois90:
Do not post partial code, the problem is rarely located in the snippets.

Maybe you're right, but my code is very long, and I need to translate lots of things from French to English... But I post all important functions, from the first call to check if a message is available to the last which do an action related to the content of the message. My program do nothing else in this time.

PaulS:
How do you KNOW when a complete message has been received? There is nothing in your snippets that indicates that "a complete message" is anything other than "everything that is in the buffer at this moment".
Well, obviously, "everything that is in the buffer at this moment" is NOT "a complete message".

I think that as soon as mySerial is available, the function returns everything. So, if mySerial is no available, I save everything that AT+CMGR=1 command has returned.

johnwasser:

String GetMsg()

{
  [...]
 
 return returnBuffer;
}

Thanks, but I don't know what your code do when it reach buffLimit. Moreover, I'm not sure this will solve my problem if I'm running out of memory.

PaulS:
There is NO excuse for wrapping the char array in a String instance. Just return a pointer to the char array.

arduino_new:
Your code will break if a line exceeds 79 characters.
And it returns an empty string if it finishes reading few data but couldn't find the line feed.

Are you talking about my code or about johnwasser's code ?
If it's about johnwasser's code, I only send nor more than 5 letters in my message, so 80 should be good to get back all the result of AT+CMGR command.

So, as I understand, I should use a pointer instead of a string for my function GetMsg().

Why do you understand that? A string is NOT a problem. A String IS. Strings and strings are NOT the same thing.

I need to translate lots of things from French to English.

No, you don’t. The compiler doesn’t understand French. It understands c++. We can read your code, no matter what language the comments are in, because they are usually useless and wrong.

PaulS:
Why do you understand that? A string is NOT a problem. A String IS. Strings and strings are NOT the same thing.

That's what you said in your post (Sep 24, 2018, 04:59 pm), no ? If not, I don't understand what I should do... (see below - read the entire message first)

PaulS:
No, you don't. The compiler doesn't understand French. It understands c++. We can read your code.

I understand what you mean, but variables and functions names are in French. And even if you can understand, others parts of the code are not very usefull. I never take the content of the message in the loop() function for example. The start of the process is to call check_SMS() and then GetMsg() and then state_msg(). After that, I call check_SMS() again. That's the most part of my code.

PaulS:
the comments are in, because they are usually useless and wrong.

Thanks to go straight to things !

I show my code and your answers to my friend who explained me what you mean by char array. But it seems that it's not as easy as using String (or Strings ? or strings ?). For example, how can I use all characters of the char array ? Because it seems that I can only use buff[1] to access character 2 etc. And as you can see, in state_msg(), I need to check all content of buff, not only 1 letter.

Moreover, I've just seen that there is a mistake on my GetMsg() function. I tried to delcare inTxt in a global variable before opening the topic, but forgot to delete the return and change the function from String to void. So, I corrected it, so it's now as it was before.

For example, how can I use all characters of the char array ?

That depends on what you mean by "use all the characters". You can print an entire string. You can see if a string contains another string. You can see if a string contains a character.

PaulS:
There is NO excuse for wrapping the char array in a String instance. Just return a pointer to the char array.

My excuse is that the OP declared the function as returning String. If you would like to re-write the OP's code to your liking, feel free.

arduino_new:
Your code will break if a line exceeds 79 characters.

Yes, it will probably crash eventually if messages greater than 79 characters are received. Since I was not being compensated for the code I figured a rough example would be better than nothing.

arduino_new:
And it returns an empty string if it finishes reading few data but couldn't find the line feed.

Yes. That is correct. It is designed to only return a non-empty message when the message is complete. If the message is not complete it returns an empty String. Did you have a different design you would like to implement. Feel free.

johnwasser:
My excuse is that the OP declared the function as returning String. If you would like to re-write the OP's code to your liking, feel free.
Yes, it will probably crash eventually if messages greater than 79 characters are received. Since I was not being compensated for the code I figured a rough example would be better than nothing.
Yes. That is correct. It is designed to only return a non-empty message when the message is complete. If the message is not complete it returns an empty String. Did you have a different design you would like to implement. Feel free.

I thought it was OP's code. Wasn't meant to criticize yours.