Understanding serial monitor data read

I'm trying to create an android app like ArduDroid that sends data via Bluetooth to and Arduino. So far I'm using appinventor for the android app. The app consists of about 12 buttons and 6 sliders. I'm looking at this info file to try and figure out what gets sent and how, from the android app:

/*
PROJECT: ArduDroid 
 PROGRAMMER: Hazim Bitar (techbitar at gmail dot com)
 DATE: Oct 31, 2013
 FILE: ardudroid.ino
 LICENSE: Public domain
*/



#define START_CMD_CHAR '*'
#define END_CMD_CHAR '#'
#define DIV_CMD_CHAR '|'
#define CMD_DIGITALWRITE 10
#define CMD_ANALOGWRITE 11
#define CMD_TEXT 12
#define CMD_READ_ARDUDROID 13
#define MAX_COMMAND 20  // max command number code. used for error checking.
#define MIN_COMMAND 10  // minimum command number code. used for error checking. 
#define IN_STRING_LENGHT 40
#define MAX_ANALOGWRITE 255
#define PIN_HIGH 3
#define PIN_LOW 2

String inText;

void setup() {
  Serial.begin(9600);
  Serial.println("ArduDroid 0.12 Alpha by TechBitar (2013)");
  Serial.flush();
}

void loop()
{
  Serial.flush();
  int ard_command = 0;
  int pin_num = 0;
  int pin_value = 0;

  char get_char = ' ';  //read serial

  // wait for incoming data
  if (Serial.available() < 1) return; // if serial empty, return to loop().

  // parse incoming command start flag 
  get_char = Serial.read();
  if (get_char != START_CMD_CHAR) return; // if no command start flag, return to loop().

  // parse incoming command type
  ard_command = Serial.parseInt(); // read the command
  
  // parse incoming pin# and value  
  pin_num = Serial.parseInt(); // read the pin
  pin_value = Serial.parseInt();  // read the value

  // 1) GET TEXT COMMAND FROM ARDUDROID
  if (ard_command == CMD_TEXT){   
    inText =""; //clears variable for new input   
    while (Serial.available())  {
      char c = Serial.read();  //gets one byte from serial buffer
      delay(5);
      if (c == END_CMD_CHAR) { // if we the complete string has been read
        // add your code here
        break;
      }              
      else {
        if (c !=  DIV_CMD_CHAR) {
          inText += c; 
          delay(5);
        }
      }
    }
  }

  // 2) GET digitalWrite DATA FROM ARDUDROID
  if (ard_command == CMD_DIGITALWRITE){  
    if (pin_value == PIN_LOW) pin_value = LOW;
    else if (pin_value == PIN_HIGH) pin_value = HIGH;
    else return; // error in pin value. return. 
    set_digitalwrite( pin_num,  pin_value);  // Uncomment this function if you wish to use 
    return;  // return from start of loop()
  }

  // 3) GET analogWrite DATA FROM ARDUDROID
  if (ard_command == CMD_ANALOGWRITE) {  
    analogWrite(  pin_num, pin_value ); 
    // add your code here
    return;  // Done. return to loop();
  }

  // 4) SEND DATA TO ARDUDROID
  if (ard_command == CMD_READ_ARDUDROID) { 
    // char send_to_android[] = "Place your text here." ;
    // Serial.println(send_to_android);   // Example: Sending text
    Serial.print(" Analog 0 = "); 
    Serial.println(analogRead(A0));  // Example: Read and send Analog pin value to Arduino
    return;  // Done. return to loop();
  }
}

// 2a) select the requested pin# for DigitalWrite action
void set_digitalwrite(int pin_num, int pin_value)
{
  switch (pin_num) {
  case 13:
    pinMode(13, OUTPUT);
    digitalWrite(13, pin_value);  
    // add your code here      
    break;
    //...this continues for each respective pin
[\code]

I understand it needs to identify a * as start reading valid data and a # as an end to reading valid data.  While working with the android app interface I quickly realized I also needed to distinguish between identifier data (which button got clicked) as well as value data (on or off, or an integer for pwm).

My questions are about Arduino though:
1). In the main loop they first check if the serial port is actually available using <1.  If the value is <1 then the port is unavailable and so return to the loop.  But I'm wondering, wouldn't execution return to the loop no matter what the value was?  So is this here because if it's <1 it will stop it's linear execution of loop() and go back to the start of loop?

2). Then it actually gets the data, assuming linear execution continued since it did find data from the port.  It checks to see if the character read is the START_CHR_CMD and if it isn't, it returns to the loop again.  Does this mean it goes back to the beginning of loop or continues execution?

More questions to follow :-)

Looks pretty crap to me - with delay()s and blocking parseInt()s and a flush() which has nothing to do with receiving data.

IMHO the examples in Serial Input Basics are more robust and also are non-blocking.

...R

Thanks, Im reading through your post and have a couple of questions. Why in this second code snippet for reading several characters with only the end marker:

const byte numChars = 32;
char receivedChars[numChars];	// an array to store the received data

boolean newData = false;

void setup() {
	Serial.begin(9600);
	Serial.println("<Arduino is ready>");
}

void loop() {
	recvWithEndMarker();
	showNewData();
}

void recvWithEndMarker() {
	static byte ndx = 0;
	char endMarker = '\n';
	char rc;
	
	// if (Serial.available() > 0) {
           while (Serial.available() > 0 && newData == false) {
		rc = Serial.read();

		if (rc != endMarker) {
			receivedChars[ndx] = rc;
			ndx++;
			[color=red]if (ndx >= numChars) {
				ndx = numChars - 1;
			}[/color]
		} else {
			[color=red]receivedChars[ndx] = '\0'; // terminate the string
			ndx = 0;
			newData = true;[/color]
		}
	}
}

void showNewData() {
	if (newData == true) {
		Serial.print("This just in ... ");
		Serial.println(receivedChars);
		newData = false;
	}
}
  1. When receiving characters and its not the end character, why do you set the ndx = numChars-1? Wouldnt this truncate the message?

  2. Why when you DO reach the end marker, do you set the receivedChars[ndx] = '\0' if you have defined the end character to be '\n' instead?

  3. At the end, why do you assure that this code reads at most 1 character at a time? I think ive read that one of the problems is that sometimes it could receive more than 1 character at a time and if your code is not ready to receive it, it just throws away the data.

  1. because C uses zero-based arrays. Character number 1 is accessed as receivedChars[0]. When you have filled that array element, you only have 1 character stored.

  2. because strings in C are terminated with a null character.

  3. it doesn't. It uses while(Serial.available()) so it can read many chars. In practice, it will usually only have one available to read.

Marciokoko:
Why in this second code snippet ...

Yes, it is truncating the data. It must leave space for the '\0' terminating character

You are mixing up two different terminating concepts. '\n' is the character that marks the end of the message. '\0' is the character that marks the end of a string. You can send messages with any end-marker that you choose but standard C/C++ functions require strings to be terminated with '\0'

why do you assure that this code reads at most 1 character at a time?

If you are referring to this "It is important to notice that each time the function recvWithEndMarker() is called it reads at most one character from the input buffer." then I apologize, the text is not up to date with the code. Thanks for pointing it out.

In fact each call to the function now reads whatever characters happen to be in the serial input buffer. In the orginal version it did only read one character at a time.

...R

Ok,

  1. So we are truncating the data. In that case if we are receiving truncated messages we would simply need to increase the const byte numChars to 64 or more.

  2. Yes I see I confused the 2 terms, end character vs string-terminating character.

Ok, armed with your latest input where I should basically replace Serial.parseInt(), delay() with this new structure, I shall attempt to re-write the original code in my post.

I still have a few questions about that original code that I would like to clear up:

  1. Why do this: if (Serial.available() < 1) return; which states that if incoming data is empty, then return to the loop?

  2. Similarly: if (get_char != START_CMD_CHAR) return; if we dont get the start char, return to the loop?

Why test for something and return to the loop?

Marciokoko:

  1. So we are truncating the data. In that case if we are receiving truncated messages we would simply need to increase the const byte numChars to 64 or more.

Yes, you need to set that value a little bigger than the biggest item you expect to receive. The truncation is just an extra protection.

  1. Why do this: if (Serial.available() < 1) return; which states that if incoming data is empty, then return to the loop?

  2. Similarly: if (get_char != START_CMD_CHAR) return; if we dont get the start char, return to the loop?

Why test for something and return to the loop?

Because we don't return to loop() if the test fails - in other words, if there is data or if there is a start char.

I thought it would be obvious that one should return if there is no work to do. Keep in mind that this code was written to make the maximum time available for other parts of an Arduino program.

I wrote it that way so the entire code would not be within {} which it would be if I had used
if (Serial.available > 0) {
Logically it behaves the same.

...R

OK so I think I'm getting it...I'm slow...

return actually exits the loop() method and starts anew from the first line of the loop(). I thought it meant it would just keep traversing the loop() as it was doing so before reaching that line...in which case it seemed pointless.

So if there is no data to be read, execution of loop() stops and exits the loop() and starts loop() because loop() is called infinitely. So it doesn't waste time traversing the rest of the loop() method.

This far I understand.

So writing:

if (Serial.available > 0) {} //if data comes in, do something that takes a long time...blocking the main thread.

But by using:

if (Serial.available < 1) {} // if no data, skip the rest of loop(, break out and restart the loop() until there is data...great!

So about:

if (get_char != START_CMD_CHAR) return; // if not START_CHR_CMD then also skip the rest of the loop() and start a new.

It's the same thing...

Marciokoko:
return actually exits the loop() method and starts anew from the first line of the loop().

Not quite.

if you have code in loop() like this

void loop() {
   myFunction1();
   myFunction2();
}

when myFunction1() completes the code continues into myFunction2().

If there is a return() within myFunction1() the code will also continue into myFunction2()

loop() will only restart when all of the functions have completed

...R

OK so I'm not sure what return is there for. I read this:

http://www.arduino.cc/en/Reference/Return

According to that, everything after the return will not be executed if the condition is met. So using your example above:

void loop() {
   myFunction1();

   return; // return1

   myFunction2();
}

void myFunction1() {
     Serial.println("first name");
       if (1=1) {
          return; // return2
          Serial.println("last name");
        }
}

void myFunction2() {
     Serial.println("middle name");
       if (1=1) {
          return; //return3
          Serial.println("nick name");
        }
}

In this case return1 will make it so only myFunction1 is executed but myFunction2 will never be executed?

In this case first name will be logged but then return2 will stop further execution of myFunction1 and return to the loop where return1 as mentioned before will stop execution of myFunction2?

I'm not at my computer, otherwise I'd test it.

Marciokoko:
So using your example above:

My example does not have return within loop()

loop() is a function with no different status from myFunction() so you can use return in loop() and it will direct the program back to the hidden main() function that called loop() in the first place.

All that return does is to return the code to the point immediately after the point at which the function (that contains the return) was called.

I don't understand what you are having difficulty with. Perhaps you can explain how you think it works - that may help me to give a more useful answer.

...R

All that return does is to return the code to the point immediately after the point at which the function (that contains the return) was called.

According to the post I put in my previous reply, anything after return is not executed. But according to you everything after return is indeed executed executed. If that is the case, what is the return being used for?

Iow, if there is no data coming into the serial port then just keep running thru the loop method? But it's already doing that, it makes me think it's superfluous. So obviously it doesn't mean keep on going, does it?

Marciokoko:
According to the post I put in my previous reply, anything after return is not executed. But according to you everything after return is indeed executed executed. If that is the case, what is the return being used for?

No. you are mixing up "afters" in two different places.

All functions are called by another (parent) function.

When a return is encountered in a child function the code immediately returns to the parent function and it does not complete any other code that comes after (1) return within the child function.

When the action gets back to the parent function it continues with the instruction after (2) the instruction that called the child function.

void loop() {
   myFunction1();
   myFunction2();
}

void myFunction1() {
    if there is nothing to do {
       return;
    }
    do other stuff
}

In this example the "do other stuff" will not happen if there is nothing to do because it comes after return.

Whether or not myFunction1() completes the code will continue with myFunction2() because it comes after the call to myFunction1().

Maybe another way to think about it is that the closing } at the end of a function is an implicit return.

...R

I just tried this:

int main()
{
    printf("Hello, World!1\n");
    return;
    //someMethod();
    printf("Hello, World!2\n");
    return 0;
}

And it prints:

Hello World1

Then I ran this:

#include <stdio.h>
void my_function();

int main()
{
    printf("Hello, World!1\n");
    //return;
    my_function();
    printf("Hello, World!2\n");
    return 0;
}

void my_function() {
    printf("Hello, World!3\n");
    return;
    printf("Hello, World!4\n");
    return;
}

And I got:

Hello World1
Hello World2
Hello World3

So going back to my original understanding, this code:

void loop(){
     if (Serial.available() < 1) return;
    //...a bunch of code
}

will essentially stop executing code in the loop() method since there is nothing to do with it. This makes sense to me.

As for these:

void loop(){
     if (Serial.available() > 0) {
}

In this case you are checking if data exists...but I understand this is less efficient?
...
or
...

void loop(){
     while (Serial.available() > 0) {
}

What about this one?

Marciokoko:
So going back to my original understanding, this code:

Hold on a moment.

Why on earth are you thinking of putting

if (Serial.available() < 1) return;

inside the function loop()

That makes zero sense and NONE of my examples or demos does it.

I need to understand why you have considered that possibility if I am to explain this further.

...R

Because that's what is in the original code I'm trying to understand. It's the code in my original post.

Marciokoko:
Because that's what is in the original code I'm trying to understand. It's the code in my original post.

Look at the first few words of Reply #1

It looks even crapper now that you have drawn my attention to that :slight_smile:

...R

Lol!

Well I asked the author but he hasn't answered. I guess it's not really possible to try to understand what he was thinking of when he wrote that.

I'll try and rewrite that code using your technique and post back for advice. Thanks