NewSoftSerial buffer problem

Hello,
I am using NewSoftSerial lib to talk to a cellular phone and Serial to debug it on my PC. I used the String library but after I read some topics about String’s bugs I decided to change it with char array (not only for the bugs but to improve my programming skills). It seems that everything works fine except one strange behaviour in the buffer in NSS.
So I choose to not use dynamic memory allocation to avoid mem fragmentation but instead I am declaring a global char array which is NULL’ed on every read. Here is the important part of the code:

#include <NewSoftSerial.h>
const int MAXSIZE=256;
char pString[MAXSIZE];
int RING =0;
NewSoftSerial phone(2, 3);
void setup()  
{
  Serial.begin(9600);
  phone.begin(9600);
}

void loop()                    
{
  if (phone.available() > 0) {
    	read_phone(); // READ PHONE                                          
	if (compString(pString,"*ECAV:",0,6)) { //compString() is my func for comparison
		//processing the details of the caller here
	} else if (strcmp(pString,"RING")==0 ) {
		RING++;
	   	Serial.print("Ringing: "); Serial.println(RING);
	} else {
	   	Serial.println(pString);
	}
  }
  memset(pString, '\0', sizeof(pString));
}

void read_phone () {
    memset(pString, '\0', sizeof(pString));
    while (phone.available() > 0) {
      if (phone.available()>=MAXSIZE)break;
      char pchar= phone.read();
      if (pchar == 0) { //exclude null char
        delay(5);          //I'll use this section later
      } else if (pchar!=13 && pchar!=10) { //exclude LF and CR
        int len = strlen(pString);
        pString[len] = pchar;
        pString[len + 1] = '\0'; //the last char is
      }				// always null
      delay(5);
    }
    phone.flush();
}

So when i call to this phone he sends the following unsolicited messages to arduino:
*ECAV: 1,6,1,“112233445566”,145
RING
RING
RING

The first line is an info about who is calling and what is the state of the connection. The “RING” string appears periodically. Here is the problem:
I thing sometimes the string “RING” comes almost in the same time with the “*ECAV” string (sometimes RING is the first). So I check for phone.available(), it says TRUE and I am starting to phone_read() the buffer where phone.available() is 8 bytes long (\10\13RING\13\10) and what I am thinking is happening here, when I read the “RING” string the phone sends the ECAV string in the same time. The “while” loop in the read_phone() makes extended loops because probably phone.available() is increased and I receive a garbage string like this:

RING*ECAV: 1,6,1,,,"112233445566",145

The ECAV string is concatenated with the RING string. Could anyone help me here. I am not sure if my troubleshooting is correct. Is this some kind of bug or there is a problem in my code. I am really happy with my new code because removing the String class decreased my code from 14500 to 12300 bytes.

Thanks!

      if (phone.available()>=MAXSIZE)break;

Every time a character is read from the phone, the pending number of bytes decreases. The size of the NewSoftSerial input buffer is less than MAXSIZE, so this condition will never be met.

It is not the number of character that remain to be read that should trigger the break. It is the number of characters remaining in the pString buffer becoming 0 that should trigger the break.

    while (phone.available() > 0) {
 // snipped some stuff...
      delay(5);
    }
    phone.flush();

Why are you delaying after reading a character? Why, after you have read all the data from the buffer do you feel it is necessary to flush the empty buffer?

    memset(pString, '\0', sizeof(pString));

From the perspective of the string functions, there is absolutely no difference between every element in the pString array containing a NULL and just the first element containing a NULL. Replace all the memset calls with

pString[0] = '\0';

If the carriage return and line feed are significant, shouldn't they cause breaking out of the while loop that is reading data?

phone.flush(); I just tested it and forgot to delete this line. if (phone.available()>=MAXSIZE)break; same as above. I debugged the length of available() and forgot to remove this line. About delay(5); in the reading - sometimes the string is cut if I dont delay it. The while cycle is faster that it can read the buffer at 9600 baud (or the data is not ready i dont know). But i found a solution which works now:

if (pchar == 0) { delay(5); Phone_init(); } else if (pchar!=13 && pchar!=10 && pchar!=0) { byte len = strlen(pString); pString[len] = pchar; pString[len + 1] = '\0'; } else { return; }

so if the strings "RING" and "ECAV..." came at the same time there are LF and CR chars between them. So now if I return to the loop() after LF/CR it calls read_phone() again and read the "ECAV.." string as new one.

That code would be more readable like so:

      if (pchar == 0)
      {
        delay(5);
        Phone_init();
      }
      else if (pchar==13 || pchar==10)
      {
        return;
      }
      else
      {
        byte len = strlen(pString);
        pString[len] = pchar;
        pString[len + 1] = '\0';
     }

Also, rather than recomputing the string length each time, define len at the top of the function, initialized to 0, and increment it after storing the character:

      byte len = 0;
      if (pchar == 0)
      {
        delay(5);
        Phone_init();
      }
      else if (pchar==13 || pchar==10)
      {
        return;
      }
      else
      {
        pString[len++] = pchar;
        pString[len] = '\0';
     }

Thank you very much, PaulS. I will replace this code and test.

P.S. About: pString[len++] = pchar; pString[len] = '\0'; Do you mean pString[len] = pchar; pString[len++] = '\0';

P.S. About: pString[len++] = pchar; pString[len] = '\0'; Do you mean pString[len] = pchar; pString[len++] = '\0';

No, I don't. Look at the difference between ++len and len++. The prefix notation (++len) increments the value of len, and then uses the value. The postfix notation (len++) uses the value of len, then increments it.

When adding the first character, len starts at 0, so pchar is stored in pString[0]. Then, len is incremented to 1, and the NULL is stored in pString[1].