Serial.parseInt bug on custom mega board?

Hi There,

I recently spun a custom mega board (based on the mega schematic). I'm having a super bizarre problem related to serial i/o. I've used the parseInt() function several times on an uno board without issue, but for some reason I'm getting some very strange behavior.

I've written a function pasted below, which is meant to service a command depending on what character it reads from the serial port. I've simplified the function to focus on the issue at hand, which is basically that I'm not getting expected behavior from parseInt().

void serviceCmd(){
  int num;
  if(Serial.available() > 0){
    char firstChar = Serial.read();
    if(firstChar == 'i'){
      num = Serial.parseInt();
      Serial.print(num);
      byte readByte;
      Serial.println();
      Serial.print(Serial.available());
      Serial.println(" bytes left...");
      while(Serial.available() > 0){
    readByte = Serial.read();
      }
    }
    else{
      Serial.print("Got unknown command: ");
      Serial.println(firstChar);
      byte readByte;
      while(Serial.available() > 0){
    readByte = Serial.read();
    Serial.print(readByte, DEC);
      }
    }
  }
}

I'd expect that if I enter "i 1234" to the terminal I should get back "1234". Here's a sample of what I enter and what I get:

Enter: "i123" Get back: 0 0 bytes left...

Enter: "i 1234" Get back: 2 2 bytes left...

Enter: "i 5678" Get back: 6 2 bytes left...

Enter: "i 9999" Get back: 9 2 bytes left...

Enter: "i 1" Get back: 0 0 bytes left...

Any suggestions here? This seems super strange to me. I'm clearly able to get data from the serial port without a hitch and I'm able to send data to the serial port, but for some reason parseInt just isn't giving me what I'd expect in any way shape or form.

Thanks!

Any suggestions here?

Yep. Don't call parseInt() when there is nothing in the serial buffer.You call it now after reading the one character that was available.

What is sending the serial data? The Serial Monitor? If so, what line ending do you have chosen?

Thanks for the reply. parseInt() is indeed called only after the first character is read out. The function first checks whether there are any bytes available, then reads the first character, and then calls parseInt(). For kicks (and to make it user, er me, proof) I added a secondary Serial.avaliable() check after first char is determined to be i such that there must be a number entered after the i. The input data is coming from the arduino IDE serial monitor with no line ending. Thanks!

You have the source code. Look at how parseInt() is implemented. Serial is an instance of HardwareSerial, which derives from Stream, where the parseInt() method is actually defined. The method waits for a character to arrive on the serial port. If that character is not a digit or a minus sign, the function discards it. If it is, the function begins building the return value. It then waits for another character to arrive. If that character is not a digit, or no character arrives within the designated time, the value that has been built is returned. If the character is a digit, the value to return is amended.

It can take a long time for parseInt() to return if data comes in slowly. If there is a 0.9 second delay between characters, and you send “1023”, the function can take 4.6 seconds to determine that there is no more data coming.

When using parseInt(), you should ALWAYS follow the integer value by some kind of non-digit separator. The linefeed and/or carriage return that the Serial Monitor can add are good delimiters.

Even better, though, is to read and store serial data as it arrives, and parse it your self when the delimiter arrives. Your program can be doing other things while serial data slowly trickles in (and that’s the only way it arrives). Then the end of the packet arrives, then you can deal with the packet.

An example of an application that reads and stores delimited packets:

#define SOP '<'
#define EOP '>'

bool started = false;
bool ended = false;

char inData[80];
byte index;

void setup()
{
   Serial.begin(57600);
   // Other stuff...
}

void loop()
{
  // Read all serial data available, as fast as possible
  while(Serial.available() > 0)
  {
    char inChar = Serial.read();
    if(inChar == SOP)
    {
       index = 0;
       inData[index] = '\0';
       started = true;
       ended = false;
    }
    else if(inChar == EOP)
    {
       ended = true;
       break;
    }
    else
    {
      if(index < 79)
      {
        inData[index] = inChar;
        index++;
        inData[index] = '\0';
      }
    }
  }

  // We are here either because all pending serial
  // data has been read OR because an end of
  // packet marker arrived. Which is it?
  if(started && ended)
  {
    // The end of packet marker arrived. Process the packet

    // Reset for the next packet
    started = false;
    ended = false;
    index = 0;
    inData[index] = '\0';
  }
}