Understanding parseint() in arduino

I am a sending 0 and 1 from a software called MaxMSP to the serial port of the Arduino.
each 0 or 1 is associated with a motor ID A to D
Those IDs states of 0 or 1 are translated to integers. so to send A 1 to arduino I'm sending a list of those numbers: 65 32 49 . That list of numbers is followed by the number 10 which is "new line" in ascii code. In the second attached picture you can see the order of data sent to arduino - first the list of integers represnting each motor state and then the number 10 that is "new line"

the arduino code I'm using is the following:

byte inByte;
//motor states; initial to Off 0;
int m1 = 0;
int m2 = 0;
int m3 = 0;
int m4 = 0;
void setup ()
{
  
  Serial.begin(115200);
  
  for(int i = 2; i < 6; i++)
  {
  pinMode(i, OUTPUT);
  }

}

void loop()
{
  if (Serial.available() > 0)
  {
    inByte = Serial.read();
    if (inByte == 'A'){m1 = Serial.parseInt();digitalWrite(2, m1);}
    if (inByte == 'B'){m2 = Serial.parseInt();digitalWrite(3, m2);}
    if (inByte == 'C'){m3 = Serial.parseInt();digitalWrite(4, m3);}
    if (inByte == 'D'){m4 = Serial.parseInt();digitalWrite(5, m4);}
  }
}

I try to understand each state in the loop that is reading the data from Max (via the serial port)

the line:

if (Serial.available() > 0)

means checking if there is any data at the serial? check if I'm currently sending any data?

if true - store that data in the variable inByte using the function Serial.read();

how does the serial.read() knows until when to read the income data? is it because we send the integer 10 after each motor state?
what doe the Serial.parseInt() do?

I don't understand the sentence:
if (inByte == 'A') the inByte is not storing only the charterer A rather also the character space (integer 32 ) and the charcter 0 or 1 (int 48 or 49)

can someone explains me how this part of the code is working?

Thanks

inByte is size byte. So it can only hold one character...
Serial.parseint() reads characters from Serial and translates them to int type. So '1' is returned as 1.
It will stop parsing when it finds something that cannot be converted to int (such as a space or a '\n` or a '\0'.
It is common practice to store characters in char, not in byte.
A switch case construction would make your code more clear.
It is not recommended to put multiple statements in one line.
Applause :clap::clap::clap::clap::clap: for using code tags and a proper description!

It only ever reads one character.

Nope. Just one character.

and the others are also ASCII codes in decimal

  • 65 is 'A'
  • 32 is space
  • 49 is '1'
  • 10 is indeed a line feed (which serves as end marker)

I would suggest to study Serial Input Basics to understand how to receive such a message and deal with it

So first of all inByte can store only one char. when inByte == 'A' we get inside the curly braces where is {m1 = Serial.parseInt()

in that point the Serial.parseInt() should reads the next available char after 'A' which is 'space' or integer 32 ? but we know this is not true and what he reads (and pass to the digitalWrite) is either 0 or 1 (48 or 49) . So where is the space (32) disappear?

because if inByte can store only one char, in that case- 'A' and the next char is space (32). which variable is storing it? or where does it went in the code?

You ask the processor to 'scan' (parse) the contents of the serial for 1 or more consecutive characters that can (together) represent an integer. The space cannot represent an int and is simply skipped.

ok so lets see if I got it:

 if (inByte == 'A'){m1 = Serial.parseInt();digitalWrite(2, m1);}. 

when inByte == 'A' we get inside the curly braces where is {m1 = Serial.parseInt();

now Serial.parseInt() is seeing ascii code for space (int 32) and therefore skip it but still continue to read the next char (?) (It stay inside those curly braces) which is 49 (ascii '1'). That char is a valid char and it get to be store inside m1 and to be written to digitalWrite ?
or before that the ParseInt() continue to scan the content of the serial - but because the next char is 'newLine' (10) and it is not a valid char he pass the previous data to m1? (49)

?

Parseint scans the whole content at once, till it has found something that can be inerpreted as an integer and it stops when it finds something afterwards that is not an int. It converts the char value to an int value "123" is converted to 123. It returns that value and you store it in m1. All this happens within your curly braces and does not depend on those curly braces.

(looks nicer if you ident the code and use spaces)

parseInt blocks until an int has been read or a timeout (default 1s) occurred (in which case it returns 0)
assuming you are lucky and the data comes within this 1s timeout (likely if it's sent by a computer just after the 'A') then indeed it will skip the space, read the value and stop at the new line which will stay in the Serial buffer.

so the first thing parseInt() is finding is either "0" or "1" (48, 49) ? because the previous character was "32" in ascii code and this is can't be converted to integer (?)
after the 48/49 that stored to m1 the parseInt() continue to look for char that can be converted to integer but because the next char is newline ascii 10 and it can't converted to int so it will go out from the curly braces to the top of the loop ?

No, it looks for a sequence of characters that can be converted to int.
If you have "x2x" it will skip 'x', store "2", find 'x' and stop parsing. Then it converts '2' to 2 and returns that value. In your code, you store that value in m1. Then the processor will proceed to digitalWrite().
If the string contains "xyx123abc", parseInt will return 123.
So, it parses the string first, and then returns the number.

I'm sending to arduino from Max two groups of chars
first the group that I marked in green and second the char I marked in red:

Screen Shot 2022-12-19 at 23.23.07

Loop is running -->
first line of code:

if (Serial.available() > 0)

True --> we get inside the first curly braces:

Next line of code:

inByte = Serial.read();

We store inside inByte the available char that could be in my case either 'A' 'B' 'C' or 'D'

Next line of code:

if (inByte == 'A'){m1 = Serial.parseInt();digitalWrite(2, m1);}

if the group of chars I marked in green is the next available so indeed (inByte == 'A') /
we get inside the curly braces :

{m1 = Serial.parseInt();digitalWrite(2, m1);}

Serial.parseInt() is scanning the buffer and he sees all the chars I marked in green? "65 32 48" ?

first char ('A') can't convert to an integer so it continue to the next char which is also can't be converted to an integer (space) , finally it arrives to "48" which can converted to integer 0. that char is converted to 0. In that point - is that 0 is store into m1 or the parseInt continue to the next char which is newline "10" and that can't be converted to int so he assign 0 to m1? or because newline "10" was send in separate group (marked in red) it is not even seen by parseInt() ?

?

edit: what I'm actually try to put my finger on is:

when you said:

No, it looks for a sequence of characters that can be converted to int.

Does the newline ascii 10" is part of the sequence of the chars I marked in green or it is belong to a different sequence ?

Are your numbers in hex?

The serial line has no clue about groups. What matters with parseInt is the timing or the type of byte received after starting recognizing a number. If there is more than 1 second before the new line, parseInt times out and does not even see the new line. If it’s less than 1s then it sees it and because it’s not a number, it stops there without removing it from the buffer

A C string ends with '\0'.
If you type

char a[] = "abc";

An array of length 4 is made and '\0' is added at the end.
That would be the place for parseint to stop.
I do not know if your sending device adds this '\0' character...

EDIT: (see post #16 below): I guess @J-M-L is right there. Parseint reads from Serial, not from c-strings.

ParseInt does not work on c-strings. Do you mean if the stream includes a trailing nul? there is no need if there is a start or end marker like the new line or a long enough pause in between two payloads

That group of three chars "abc" are size of three bytes or one byte?
the parseint() cannot read more then 1 byte at a time isn't it?

I do send an ascii 10 after my data in order to sign end of data stream
so I'm sending "65 32 48" together then I'm sending just right after "10"

When you put text within double quotes in C++ you create a string literal. The compiler allocates enough memory for the text and stores the UTF8 codes for the symbols you used (so ASCII codes if you used no extended character sets like éöû…) and adds a trailing null char to denote the end of the text. So "abc" has 3 characters needing in ASCII only one byte so it takes 3 bytes and then you have the trailing null.

So if you do

char text[] = "abc";

You created a 4 byte array.

It is not really relevant now (see post #16), but the array would occupy 4 bytes. One for each character plus the '\0'.