// 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