Why does a Static unsigned int initialized within a while loop not reset itself?

Hi, I’ve been trying to understand Serial and tried to follow this code for creating a buffer for data coming in through Serial: Gammon Forum : Electronics : Microprocessors : How to process incoming serial data without blocking

I understand it’s kind of old but it seems the sketch doesn’t use anything that’s deprecated so I still tried to follow it.

My question is, within the sketch itself it does a while loop when data is available:

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

  }  // end of loop

and calls the processIncomingByte() function taking the data from the Serial using Serial.read() as an argument. The function takes each character from the data as a byte and stores it in a character array using switch statements to determine when it stops storing (when ‘\n’ is detected). What I don’t understand is this:

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

Inside the processIncomingByte() function, it initializes the static unsigned integer variable “input_pos” to 0.

  1. Why does it not reset after every while loop instance that “Serial.read()” is made if it is initialized over and over again per character of the input data?

  2. why does the while loop not have “{ }” in the sketch as well?

  3. how does a Byte of data can directly be stored in a char array? Shouldn’t it be converted first?

  4. I tried to get the raw data of any incoming input data I put in through the Serial monitor by Serial.print() but it always comes out as the ASCII representation. Is there a way to print the RAW bits of the characters I send?

  5. I tried to understand it by placing a Serial.write() to provide data but it seems Serial.read() does not recognize it. Why is writing data through Serial.write() not work?

Note: If I misunderstood anything about how the sketch works, any comments would be much appreciated. Thank you!

NateWillis:

  1. Why does it not reset after every while loop instance that "Serial.read()" is made if it is initialized over and over again per character of the input data?

This is how local static variables work. The whole point of making it static is so that it will retain its previous value where a non-static would not once it goes out of scope. so it's essential that the variable only be initialized once:
https://www.arduino.cc/reference/en/language/variables/variable-scope--qualifiers/static/

NateWillis:
2) why does the while loop not have "{ }" in the sketch as well?

while, if, for, etc. only need braces if you want them to affect multiple lines of code. Since the code's author only needed a single line of code in the while loop, they didn't bother with braces. However, you need to be very careful if you follow this practice because it's a common source of bugs for someone to add more lines of code thinking they will also be in the while loop, when really they are not. My advice is to always use braces. There is no penalty except for a couple of keystrokes and a little bit of vertical whitespace. It makes the intent of your code more clear. I think even if using braces only ever causes you to avoid one bug over your programming career it will have paid off.

NateWillis:
3) how does a Byte of data can directly be stored in a char array? Shouldn't it be converted first?

It's converted at the time of the assignment to the array. However, I think it would have been more appropriate to use the char type in this case. The choice of type communicates the intent of the code.

NateWillis:
4) I tried to get the raw data of any incoming input data I put in through the Serial monitor by Serial.print() but it always comes out as the ASCII representation. Is there a way to print the RAW bits of the characters I send?

The behavior of print() depends on the type of the argument (it's an overloaded function). If you pass it a byte, then it's going to print the base 10 numerical decimal representation of that value. If you pass it a char, then it will print the ASCII character associated with that value. You can use Serial.write() to always print the ASCII character associated with that value.
https://www.arduino.cc/reference/en/language/functions/communication/serial/write

NateWillis:
5) I tried to understand it by placing a Serial.write() to provide data but it seems Serial.read() does not recognize it. Why is writing data through Serial.write() not work?

I don't understand the question. Please provide a minimal sketch that demonstrates what you tried to do and a more detailed explanation of what you expected to happen and what happened instead of what you expected.

NateWillis:
5) I tried to understand it by placing a Serial.write() to provide data but it seems Serial.read() does not recognize it. Why is writing data through Serial.write() not work?

Serial.write() sends a character out through the serial port, typically to be displayed on Serial Monitor. It does not come back in through the Serial.read(). You could do it by wiring the Transmit (TX) pin to the Receive (RX) pin but then you couldn't use Serial Monitor to see what was happening.

Thank you both for the insightful replies.

6 ) So a local static variable needs to only be initialized once? In the sketch "static unsigned int input_pos = 0;" wouldn't the variable be affected by that same line of code every time the function is called? From the example on the documentation page, I would understand it retaining the value since when it was defined, there was no constant assignment and only operations with variables were placed on the right hand side. But in this sketch, it assigns a 0 to it within the function. Wouldn't that overwrite the previous value regardless?

pert:
I don't understand the question. Please provide a minimal sketch that demonstrates what you tried to do and a more detailed explanation of what you expected to happen and what happened instead of what you expected.

Below is the code I tried to place in the sketch. I placed Serial.read() and printed out its result after I noticed Serial.available() doesn't recognize Serial.write("JAM") as data "available" thereby not calling processIncomingByte(). And when I tried placing Serial.print(Serial.read()) it still outputs invalid (-1) meaning it doesn't recognize Serial.write() as data.

void loop()
  {
  delay(750);
  Serial.write("JAM");                   //Attempt of test input of "JAM" to make data "available" to Serial.
  Serial.println("");
  Serial.println(Serial.read());       

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

  }  // end of loop

This is the output:

I looked into Serial.read() and supposedly it should output the characters if it finds valid data and -1 if it doesn't.

It seems johnwasser's reply answers this:

johnwasser:
Serial.write() sends a character out through the serial port, typically to be displayed on Serial Monitor. It does not come back in through the Serial.read(). You could do it by wiring the Transmit (TX) pin to the Receive (RX) pin but then you couldn't use Serial Monitor to see what was happening.

7 ) Won't Serial.write() send it to a connected device on the other end and have a connecting device do Serial.read() on the other end to accept that data and process it? Like what you said about hooking up TX and RX (so far how I see it is that the Serial Monitor isn't the one to "receive" what Serial.write() input "JAM" and therefore did not see it through Serial.read()). However hypothetically, if there was another device on the other end doing "Serial.read()" it should receive what the other device "Serial.write()"-ed?

pert:
The behavior of print() depends on the type of the argument (it's an overloaded function). If you pass it a byte, then it's going to print the base 10 numerical decimal representation of that value. If you pass it a char, then it will print the ASCII character associated with that value. You can use Serial.write() to always print the ASCII character associated with that value.
Serial.write() - Arduino Reference

8 ) When I tried to output the byte using Serial.print(inByte,BIN); it only shows 7 bits. Is the function removing leading 0s?

Thank you again, this is all an attempt in trying to understand how Serial works between two devices. I'm trying to communicate between two devices (or Arduinos) with SoftwareSerial while maintaining the hardware Serial to monitor the outputs with handshaking. I tried to do it with available sketches online but found that my understanding of Serial lacking so I started with buffering sent inputs from the Serial Monitor first.

NateWillis:
But in this sketch, it assigns a 0 to it within the function. Wouldn't that overwrite the previous value regardless?

No, it is not assigned a 0 within the function. It is initialized to to 0 in the function. Local static variables are only initialized the first time control passes through that point.

If you WANT it to reset to 0 each time:

void processIncomingByte (const byte inByte)
  {
  static char input_line [MAX_INPUT];
  static unsigned int input_pos;

  input_pos = 0;

  switch (inByte)

But then there would be no reason to make it ‘static’ so you might as well write:

void processIncomingByte (const byte inByte)
  {
  static char input_line [MAX_INPUT];
  unsigned int input_pos;

  input_pos = 0;

  switch (inByte)

Which is functionally equivalent to:

void processIncomingByte (const byte inByte)
  {
  static char input_line [MAX_INPUT];
  unsigned int input_pos = 0;

  switch (inByte)

Don't confuse initializing with assigning.

static int input = 0; //this is an initialization statement

input = 0; //this is an assignment statement

NateWillis:
I noticed Serial.available() doesn't recognize Serial.write("JAM") as data "available"

Serial.write() is sending outgoing data. Serial.available() tells you whether there is incoming data. So of course Serial.write() will have no effect on Serial.available(). If you want to send data to your Arduino, just type it in on the input field of Serial Monitor and click the "Send" button.

NateWillis:
7 ) Won't Serial.write() send it to a connected device on the other end and have a connecting device do Serial.read() on the other end to accept that data and process it?

If that's what you have set up, yes. In this case, the "connected device" is your computer running Serial Monitor. It's doing something similar to Serial.read(), but the Serial Monitor is written in the Java programming language so the Serial Monitor source code would look different than Arduino code you wrote to receive serial data.

NateWillis:
so far how I see it is that the Serial Monitor isn't the one to "receive" what Serial.write() input "JAM"

How can you say that when your screenshot clearly whows that Serial Monitor did receive "JAM"?

NateWillis:
8 ) When I tried to output the byte using Serial.print(inByte,BIN); it only shows 7 bits. Is the function removing leading 0s?

Yes.

NateWillis:
I started with buffering sent inputs from the Serial Monitor first.

What do you mean by "buffering"? It seems like you might not understand how Serial Monitor works. When Serial Monitor receives data from the serial port, it displays it on the output window. When you type text into Serial Monitor's input field and click the "Send" button, it sends that data over the serial port. That's all Serial Monitor does.

Thank you all again for your answers to all my questions and clearing some wrong assumptions I had. I'll try to self-study better and won't ask anymore questions. Thank you!

You're welcome. I'm glad if I was able to be of assistance.

I think it's a good idea to do some research to see if you can answer your own questions, if only because it's often faster than waiting for someone to reply to your forum post. However, please don't be afraid to ask questions here. That's what the forum is all about and we're always happy to help as long as people use the forum in a respectful manner (which you certainly have done).

Inside the processIncomingByte() function, it initializes the static unsigned integer variable “input_pos” to 0.

  1. Why does it not reset after every while loop instance that “Serial.read()” is made if it is initialized over and over again per character of the input data?

Because that’s what static varables do. static means that the variable is placed in a global, persistent, static area rather than being kept on the transient stack.

  1. why does the while loop not have “{ }” in the sketch as well?

the while() statment operates on a single statement. A single statement can be an expression with a semicolon on the end, a block of statements in braces, or one of the other controll statments (while, if, do)

  1. how does a Byte of data can directly be stored in a char array? Shouldn’t it be converted first?

C++ does several automatic type conversions for primitive types like char, int, byte, etc

  1. I tried to get the raw data of any incoming input data I put in through the Serial monitor by Serial.print() but it always comes out as the ASCII representation. Is there a way to print the RAW bits of the characters I send?

Because that’s what serial monitors do. Serial monitors thake incoming bytes and display the ASCII representation of that byte. If a serial monitor receives a 65 over the connection, it will display an uppercase letter ‘A’. Some serial monitor software might - for instance - additionally display the hexadecimal number. If you want the arduino IDE monitor to display a binary number, you’ll have to send it a series of ascii characters - you’ll have to do the conversion yourself. Happily, this isn’t difficult:

void printByteAsBinary(byte b) {
  for(int bit = 7; bit >= 0; bit--) {
    if(b & (1<<bit)) 
      Serial.print('1');
    else
      Serial.print('0');
  }
}
  1. I tried to understand it by placing a Serial.write() to provide data but it seems Serial.read() does not recognize it. Why is writing data through Serial.write() not work?

Serial.write sends data to the USB. The arduinos IDE software reads this and puts it on the monitor.
Serial.read reads data from the USB. The arduino IDE software sends data to the arduino when you type stuff into the textbox at the bottom of the monitor form and hit return.