Serial event example revised

I'm working on an interpreter, so I started with the serial event example from the IDE:

String inputString = "";         // a String to hold incoming data
bool stringComplete = false;  // whether the string is complete

void setup() {
  // initialize serial:
  Serial.begin(9600);
  // reserve 200 bytes for the inputString:
  inputString.reserve(200);
}

void loop() {
  // print the string when a newline arrives:
  if (stringComplete) {
    Serial.println(inputString);
    // clear the string:
    inputString = "";
    stringComplete = false;
  }
}

/*
  SerialEvent occurs whenever a new data comes in the hardware serial RX. This
  routine is run between each time loop() runs, so using delay inside loop can
  delay response. Multiple bytes of data may be available.
*/
void serialEvent() {
  while (Serial.available()) {
    // get the new byte:
    char inChar = (char)Serial.read();
    // add it to the inputString:
    inputString += inChar;
    // if the incoming character is a newline, set a flag so the main loop can
    // do something about it:
    if (inChar == '\n') {
      stringComplete = true;
    }
  }
}

but I'm just not a fan of the String or the std::string classes, so I revised it a bit:

const uint16_t input_buffer_size = 256;
      char     input_char;
      char     input_buffer[input_buffer_size] = ""; 
      uint8_t  input_buffer_index = 0;      
      bool     input_available = false; 

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

void loop() {
  if (input_available) {
    Serial.println(input_buffer);
    input_buffer[0] = 0;
    input_buffer_index = 0;    
    input_available = false;
  }
}

void serialEvent() {
  while (Serial.available()) {
    input_char = (char)Serial.read();
    if (input_char == '\n') {
      input_available = true;
      input_buffer[input_buffer_index] = 0;
    } else if (input_buffer_index < input_buffer_size){  
      input_buffer[input_buffer_index++] = input_char;
    } else {
      input_available = true;
      input_buffer[input_buffer_size - 1] = 0;
      Serial.flush();
    }
  }
}

There are threads that incorporate a start and stop character, but as this is just for serial monitor input, I didn't see any of that as necessary for this application.

Did I miss anything important?

This only has an effect on serial output, not on input.

I could just tick off the remaining bytes with a while loop, or is there a better way?

What do you think that Serial.flush() does?

Should that be '\0' instead of just 0?

I thought it dumped the rest of the input buffer. I see now that I was mistaken.

I thought ASCII 00 == NULL

That is why the question. I've always seen '\0' as the terminator. I don't know if 0 in that place is the same.

It is; you can print a c-string in hex including the terminating character to see :wink:

But I think that '\0' is cleaner when using c-strings.

Same thing as with conversion of numeric characters to number. Subtracting '0' is cleaner (my opinion) than subtracting 48 or 0x30 although the effect is the same; but all three will give the same result.

const uint16_t input_buffer_size = 256;
      char     input_char;
      char     input_buffer[input_buffer_size] = ""; 
      uint8_t  input_buffer_index = 0;      
      bool     input_available = false; 

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

void loop() {
  if (input_available) {
    Serial.println(input_buffer);    
    input_available = false;
    input_buffer[0] = '\0';
    input_buffer_index = 0;
  }
}

void serialEvent() {
  while (Serial.available()) {
    if (input_buffer_index >= input_buffer_size) {
      Serial.println("Input buffer overrun"); 
      while (Serial.available()) Serial.read();
      input_buffer[0] = '\0';
      input_buffer_index = 0;
    } else {
      input_char = (char)Serial.read();
      if (input_char == '\n') { // Terminate buffer
        input_buffer[input_buffer_index] = '\0';
        input_available = true;
      } else { // Buffer character
        input_buffer[input_buffer_index++] = input_char;
      }
    }
  }
}

You can dump that in a function that you call :wink:

I had considered that.
Here's the question that came with it.
How heavy does a block of code need to be to benefit being put into a function?
Though not as critical here, my next project will have to consider that question more.

For me, it's not how heavy the block of code is, it's far more about how readable it is.

PS:
You are aware that Robin2 already did write a tutorial on serial communication? It doesn't use serialEvent. Serial Input Basics - updated

I am. It's a great article that works for a lot of boards.

This is important for universal applicability. I'm just coding this for the 328 and 2650, so it's ok to use it, but I do recognize the importance of knowing how to do it without the event.

Good feedback, thank you.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.