Serial Echo code breakdown [beginner]

Hello, this is my first post on this forum. I’m fairly new to both Arduino and C programming, I’ve been playing around for a couple of days now.
I was really interested in creating a simple sketch that would echo any input from the serial monitor, but since it turned out not easy enough for me, I looked up a working code online. I would like to fully understand how it works, so a basic breakdown from a more experienced user is what I need.
The code has been commented pretty nicely, but I still have some questions.

/*
Example of processing incoming serial data without blocking.

Author:   Nick Gammon
Date:     13 November 2011. 
Modified: 31 August 2013.

Released for public use.
*/

// how much serial data we expect before a newline
const unsigned int MAX_INPUT = 50;

void setup ()
  {
  Serial.begin (115200);
  } // end of setup

// here to process incoming serial data after a terminator received
void process_data (const char * data)
  {
  // for now just display it
  // (but you could compare it to some value, convert to an integer, etc.)
  Serial.println (data);
  }  // end of process_data
  
void processIncomingByte (const byte inByte)
  {
  static char input_line [MAX_INPUT];
  static unsigned int input_pos = 0;

  switch (inByte)
    {

    case '\n':   // end of text
      input_line [input_pos] = 0;  // terminating null byte
      
      // terminator reached! process input_line here ...
      process_data (input_line);
      
      // reset buffer for next time
      input_pos = 0;  
      break;

    case '\r':   // discard carriage return
      break;

    default:
      // keep adding if not full ... allow for terminating null byte
      if (input_pos < (MAX_INPUT - 1))
        input_line [input_pos++] = inByte;
      break;

    }  // end of switch
   
  } // end of processIncomingByte  

void loop()
  {
  // if serial data available, process it
  if (Serial.available () > 0)
    processIncomingByte (Serial.read ());
    
  // do other stuff here like testing digital input (button presses) ...

  }  // end of loop

The biggest mystery:

void process_data (const char * data)

what does the phrase in the brackets do?

Is using ‘unsigned’ propert neccessary?

const unsigned int MAX_INPUT = 50;

Then the whole processIncomingByte function. I think that by now I understand the basic use of arrays (or whatever the thing is). Still, the use of input_pos and input_line remain unclear.

Before someone starts bashing me for it: I did use google, but what I found was mostly too advanced for me to understand. Help is much appreciated :slight_smile:

There are a few geeky programming things in that sketch. It's normal if not everything is clear.

The 'unsigned' for MAX_INPUT is not needed, it can be a normal integer.

This is a declaration of a function:

void process_data (const char * data)

You can read it as this:

something_returned NameFunction (parameters)

The "void" in front is what is returned. In this case nothing, and the "void" word is used instead of "nothing". The "process_data" is the function name, it can be anything you made up. The parameters is in this case "const char * data". If you see a '*' you should say 'pointer'. It is: "constant character pointer data". Meaning that "data" is pointer to characters. The "const" is just added to indicate the the data is not changed inside the function.

The expression:

void process_data (const char * data)

is what is called a function signature and is used by the compiler to identify a function. (If it had a semicolon at the end of the line, it would be called a function prototype.) The word void is called the function type specifier. Every function has the ability to return a value to whatever invoked that function. The word void for this type specifier simply means that this function does not return a value.

Next, process_date is simply the name of the function.

Next, the const keyword means that whatever follows is to be etched in stone and cannot be changed. When used in parentheses following a function name, it means that the data item passed into this function cannot be changed by the function.

Next, the char * data is the actual data being passed into the function. Using Purdum's RIght-Left Rule, you can verbalize this data item as: "data is a pointer to char". Pointers are often difficult for new programmers to understand, but worth knowing. A valid pointer can have only two possible values: 1) the memory address of a data type, or 2) null (binary 0, or '\0'). What we are saying here is that, if it is a valid, non-null pointer, it points to a memory address where a character named data lives.

Hope that helps.

I was really interested in creating a simple sketch that would echo any input from the serial monitor, but since it turned out not easy enough for me,

very simple

String readString;

void setup() {
  Serial.begin(9600);
  Serial.println("serial test 0021"); // so I can keep track of what is loaded
}

void loop() {

  while (Serial.available()) {
    delay(2);  //delay to allow byte to arrive in input buffer
    char c = Serial.read();
    readString += c;
  }

  if (readString.length() >0) {
    Serial.println(readString);

    readString="";
  } 
}

Thanks for the code, it is a lot easier to understand. One thing though, could you explain why char c has to be added to an empty string before printing it? Can't we just print it right away? Or is it because having the data stored in a string allows for a lenght check?

Can't we just print it right away?

sure:

char INFO;

void setup (){
  Serial.begin (9600);
}

void loop ()
{
  if(Serial.available ())  
  {
    INFO = Serial.read();
    Serial.println(INFO);
    Serial.println();
  }
}

The 'unsigned' for MAX_INPUT is not needed, it can be a normal integer.

Is it reasonable, though, to assign -42 to MAX_INPUT? The unsigned prevents that kind of mistake.

Since MAX_INPUT is going to be used to size an array, it MUST be positive. Again, unsigned prevents assigning a negative value. It doesn't prevent assigning 0 which is also invalid, but you can only go so far with idiot-proofing your code.