/* 
Example of state machine
Author: Nick Gammon, Date: 5 December 2013

Ernter 'R' or 'S' with a positive or negitive number.
R12 S456 R-89 S20
*/

// the possible states of the state-machine
typedef enum {
  STATE_NONE, 
  STATE_R, 
  STATE_S, 
  STATE_POSITIVE, 
  STATE_NEGATIVE
  } states;


states state = STATE_NONE; // current state-machine state

void setup () { 
  Serial.begin (115200);
  Serial.println (F("Starting ..."));
  }

  
void loop () {
  if (Serial.available ())
    processInput ();
    
  // do other stuff here
}

// - - - - - - FUNCTIONS - - - - - -
  
void doRotate(const long angle) { // rotate to desired angle 
  Serial.print (F("Rotating to "));
  Serial.println (angle); 
}
  
void doSpeed(const long speed) { // set to desired speed 
  Serial.print (F("Setting speed to "));
  Serial.println (speed); 
}
  
void processNumber(char command, long n) {
  switch (command) {
    case 'R' : doRotate(n); 
    break;
    case 'S' : doSpeed(n); 
    break;
  }
}
  
void unexpectedInput (char c) {
  Serial.print (F("Unexpected input: '"));
  Serial.print (char (c));
  Serial.println (F("'"));
}

long receivedNumber = 0; // current number
char commandType; // what command we received
 
void gotSpace () {
  switch (state) {
    case STATE_NONE:

    case STATE_R:

    case STATE_S:
      break;  // ignore space 

    case STATE_POSITIVE:
      processNumber (commandType, receivedNumber);
      state = STATE_NONE;
      break; 

    case STATE_NEGATIVE:
      processNumber (commandType, -receivedNumber);
      state = STATE_NONE;
      break; 
  } 
}
  
void gotNewline () {
  switch (state) {
    case STATE_NONE: 
         break;  // ignore newline/carriage-return

    case STATE_R:

    case STATE_S:
      Serial.print (F("Unexpected line ending."));
      state = STATE_NONE;
      break;
          
    case STATE_POSITIVE:
      processNumber (commandType, receivedNumber);
      state = STATE_NONE;
      break; 

    case STATE_NEGATIVE:
      processNumber (commandType, -receivedNumber);
      state = STATE_NONE;
      break; 
  }
}
  
void gotR (const char c) {
  commandType = 'R';
  receivedNumber = 0;
    
  switch (state) {
    case STATE_NONE: 
      state = STATE_R;
      break;

    case STATE_R:

    case STATE_S:
      unexpectedInput (c);
      state = STATE_R;
      break; 
          
    case STATE_POSITIVE:
      processNumber (commandType, receivedNumber);
      state = STATE_R;
      break; 

    case STATE_NEGATIVE:
      processNumber (commandType, -receivedNumber);
      state = STATE_R;
      break; 
  }  
}
  
void gotS (const char c) {
  commandType = 'S';
  receivedNumber = 0;

  switch (state) {
    case STATE_NONE: 
      state = STATE_S;
      break;

    case STATE_R:

    case STATE_S:
      unexpectedInput (c);
      state = STATE_S;
      break; 
          
    case STATE_POSITIVE:
      processNumber (commandType, receivedNumber);
      state = STATE_S;
      break; 

    case STATE_NEGATIVE:
      processNumber (commandType, -receivedNumber);
      state = STATE_S;
      break; 
  } 
}
  
void gotDigit (const char digit) {
  switch (state) {
    case STATE_NONE: 
      unexpectedInput (digit);
      break;

    case STATE_R:

    case STATE_S:
      state = STATE_POSITIVE;
      break; 
          
    case STATE_POSITIVE:

    case STATE_NEGATIVE:
      break; 
  } 
  receivedNumber *= 10;
  receivedNumber += digit - '0'; 
}
  
void gotMinus (const char c) {
  switch (state) {
    case STATE_NONE:

    case STATE_POSITIVE:

    case STATE_NEGATIVE:
      unexpectedInput (c);
      state = STATE_NONE;
      break; 

    case STATE_R:

    case STATE_S:
      state = STATE_NEGATIVE;
      break;     
  } 
}
  
void gotPlus (const char c) {
  switch (state) {
    case STATE_NONE:

    case STATE_POSITIVE:

    case STATE_NEGATIVE:
      unexpectedInput (c);
      state = STATE_NONE;
      break; 

    case STATE_R:

    case STATE_S:
      state = STATE_POSITIVE;
      break;     
  }
}
  
void gotOther (const char c) {
  switch (state) {
    case STATE_NONE:

    case STATE_R:

    case STATE_S:

    case STATE_POSITIVE:

    case STATE_NEGATIVE:
      unexpectedInput (c);
      state = STATE_NONE;
      break; 
  }  
}
  
void processInput () {
  byte c = Serial.read ();

  // process according to what the input was  
  switch (toupper (c)) {
    case ' ':
      gotSpace ();
      break;
      
    case '\n':

    case '\r':
      gotNewline ();
      break;
      
    case 'R':
      gotR (c);
      break;

    case 'S':
      gotS (c);
      break;
      
    case '0' ... '9': 
      gotDigit (c);
      break;
      
    case '-':
      gotMinus (c);
      break;

    case '+':
      gotPlus (c);
      break;
      
    default:
      unexpectedInput (c);
      break;
  }
}