Serial.parseInt() question

I have never used Serial.parseInt() and need to ask a question about it.

The reference documentation indicates that Serial.parseInt() returns 0 if it times out without receiving any digits or (if SKIP_NONE is specified) it receives a non-numeric character.

So if the user actually enters a 0, and 0 is a valid input value for the application, how does one differentiate between the timeout/non-numeric return value and the valid 0 input value?

Perhaps I missed something on the reference page for parseInt(), but I did not see how to answer the above question.

Thanks and best regards,
DuinoSoar

No you have not missed anything parseInt() and the atoi() it is based on is not very exact.
Use this alternative code

String input = Serial.readString(); // read until input stops coming 
// or use String input = Serial.readStringUntil('\n'); // read until newline or input stops coming
input.trim(); // remove leading trailing white space e.g. CR etc
int result = input.toInt(); // actually returns a long so may be throwing away something here saving in an int result
if (input != (String(result))) {
   Serial.print(input); Serial.println(F(" is not an integer"));
} else {
  // input a valid int
}

A possible downside of the code above is that if the input is something like
334 test
then Serial.parseInt() will automatically pick out the 334 and stop at the space where as the code I have shown above will try and convert the whole input line to an int.
If your input is like 334 test, you will need to use indexOf and substring to pull out the first integer part and then convert it.

See my tutorial on Arduino Software Solutions for various ways to read from Serial with their pros and cons.

Edit – there is an alternative c function strtol() that is better than atoi() but it takes more code to use and check the result. See the toInt() method in my SafeString library (available from the library manager) for example code using strtol() and checking the result is valid.

You could use Serial.peek(); to see what character is coming next. Throw away input until you see the next character is a digit, then call .parseInt(). Allow digit or ‘-’ if you want to allow negative numbers.

For .parseFloat(), allow ‘.’ as well.

Then you know that any zero is because someone entered ‘0’ (or ‘-’).

Thank you.

I am not quite so familiar with C++, and it has been a loooonnnng time since I was familiar with the C libraries. (So I had completely forgotten about atoi function, and did not previously know about the String.toInt method; funny that it is called “toInt” but returns long.)

Actually, the code in your reply is very close to what I want. In my project, the user is being prompted to enter a positive integer. So if the input string (delimited by the \n and trimmed) contains any non-numeric character, or represents a number less than 0, I want it to fail, but I do want 0 to be a legitimate input. Also, even if it contains a legitimate number followed by non-numeric characters (as Serial.parseInt would seem to allow), I still want it to be treated as an error. (So your “possible downside” comment about .toInt vs. parseInt is not a downside at all! :grinning: ).

Thanks and best regards,
DuinoSoar.

So here’s what I got.

void ChangeParameter(int * pParameter, int minValue, int maxValue)
{
  Serial.setTimeout(10000); // Wait up to 10 seconds for input.
  String inStr = Serial.readStringUntil('\n');
  Serial.setTimeout(1000);  // return to default timeout value

  inStr.trim();
  int inValue = inStr.toInt();
  if ((inStr != String(inValue)) || (inValue < minValue) || (inVlaue > maxValue)) {
    Serial.print(F("Input value out of range or invalid. Parameter value remains the same: "));
    inValue = *pParameter;
  }
  else {
    Serial.print(F("Parameter value changed to: "));
    *pParameter = inValue;
  }
  Serial.println(inValue);
}

I haven’t tested it yet. (Maybe tomorrow. It’s late here in Atlantic Canada, and close to beddie-bye time :sleeping: ). Just realised there should be a check added to ensure minValue < maxValue.

long is short for long int

but a long (on most boards) can hold larger numbers than an int so if you assign the result of toInt() to an int as the name suggests you can loose the real result.
It should be named toLong()

And being the sort of pedantic person that I normally am, I tend to agree with the good doctor (@drmpf)

And speaking of pedantry, I am about to post a new (very pedantic :grinning: ) question about Arduino AD converters (starting a new thread, of course.)

And @killzone_kid: "long is short for long int" - I see what you did there! :wink: