// https://wokwi.com/projects/409963275966630913
// Code from https://www.gammon.com.au/forum/?id=11425&reply=1#reply1
// Other simulations https://forum.arduino.cc/t/wokwi-simulations-for-arduino-built-in-examples/1304754

// See also Serial Example 1: https://wokwi.com/projects/409963075177910273 
// See also Serial Example 2: https://wokwi.com/projects/409963275966630913 

/*
State Machine for reading Serial commands


Another way of processing incoming data, without blocking, 
is to set up a "state machine". Effectively this means looking 
at each byte in the input stream, and handling it depending on 
the current state.

As an example, say you had this coming into the serial port:

        R4500S80G3

Where Rnnn is RPM, Snnnn is speed, and Gnnnn is the gear setting.

The state machine below switches state when it gets a letter 
"R", "S" or "G". Otherwise it processes incoming digits by 
multiplying the previous result by 10, and adding in the new one.

When switching states, if first handles the previous state. So for 
example, after getting R4500 when the "S" arrives, we call the 
ProcessRPM function, passing it 4500.

This has the advantage of handling long messages without even 
needing any buffer, thus saving RAM. You can also process message 
as soon as the state changes, rather than waiting for end-of-line.

*/


// Example state machine reading serial input
// Author: Nick Gammon
// Date: 17 December 2011

// the possible states of the state-machine
typedef enum {  NONE, GOT_R, GOT_S, GOT_G } states;

// current state-machine state
states state = NONE;
// current partial number
unsigned int currentValue;

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

void processRPM (const unsigned int value)
{
  // do something with RPM 
  Serial.print ("RPM = ");
  Serial.println (value);
} // end of processRPM

void processSpeed (const unsigned int value)
{
  // do something with speed 
  Serial.print ("Speed = ");
  Serial.println (value);
} // end of processSpeed

void processGear (const unsigned int value)
{
  // do something with gear 
  Serial.print ("Gear = ");
  Serial.println (value);  
} // end of processGear

void handlePreviousState ()
{
  switch (state)
  {
  case GOT_R:
    processRPM (currentValue);
    break;
  case GOT_S:
    processSpeed (currentValue);
    break;
  case GOT_G:
    processGear (currentValue);
    break;
  }  // end of switch  

  currentValue = 0; 
}  // end of handlePreviousState

void processIncomingByte (const byte c)
{
  if (isdigit (c))
  {
    currentValue *= 10;
    currentValue += c - '0';
  }  // end of digit
  else 
  {

    // The end of the number signals a state change
    handlePreviousState ();

    // set the new state, if we recognize it
    switch (c)
    {
    case 'R':
      state = GOT_R;
      break;
    case 'S':
      state = GOT_S;
      break;
    case 'G':
      state = GOT_G;
      break;
    default:
      state = NONE;
      break;
    }  // end of switch on incoming byte
  } // end of not digit  
  
} // end of processIncomingByte

void loop ()
{
  while (Serial.available ())
    processIncomingByte (Serial.read ());

  // do other stuff in loop as required
  
}  // end of loop