/* Test program for incremental encoder state machine code */
/* Serial input aspects are based closely upon: 
   http://forum.arduino.cc/index.php?topic=396450
   Example 4 - Receive a number as text and convert it to an int
   Modified to read a float */

long int count = 0;
long int error = 0;
enum states{state1=1, state2, state3, state4};
bool channelAState;
bool channelBState;

int state;
const byte numChars = 32;
char receivedChars[numChars];   // an array to store the received data

boolean newData = false;

void setup() {
    Serial.begin(9600);
    Serial.println("Enter initial state as a 2-digit number e.g. 01 then hit return");
    do {
      recvWithEndMarker();
    } while (!newData);
    channelAState = receivedChars[0]!='0';
    channelBState = receivedChars[1]!='0';
    
    initialiseEncoderStateMachine();  
    Serial.print(state);
    Serial.print('\n');

    Serial.println("Now keep entering state as a 2-digit number e.g. 01 then hit return.");
    newData = false;
}

void loop() {
    recvWithEndMarker();
    if (newData)
    {
        channelAState = receivedChars[0]!='0';
        channelBState = receivedChars[1]!='0';
        updateEncoderStateMachine();
        Serial.print("State: ");
        Serial.print((int)state);
        Serial.print(" Count: ");
        Serial.print(count);
        Serial.print(" Error: ");
        Serial.print(error);
        Serial.write('\n');
        newData = false;
    }
    
}

void recvWithEndMarker() {
    static byte ndx = 0;
    char endMarker = '\n';
    char rc;
    
    while (Serial.available() > 0 && newData == false) {
        rc = Serial.read();

        if (rc != endMarker) {
            receivedChars[ndx] = rc;
            ndx++;
            if (ndx >= numChars) {
                ndx = numChars - 1;
            }
        }
        else {
            receivedChars[ndx] = '\0'; // terminate the string
            ndx = 0;
            newData = true;
        }
    }
}

void initialiseEncoderStateMachine()
{
  /* If initially A is 0 and B is 0, system starts in State 1
     If initially A is 1 and B is 0, system starts in State 2
     If initially A is 1 and B is 1, system starts in State 3
     If initially A is 0 and B is 1, system starts in State 4 */

  if (channelAState)
  {
      if(channelBState)
      {
        state = state3;
      }
      /* else ....  lots of code goes here */
  }
}

void updateEncoderStateMachine()
{
  switch (state)
  {
     case state1:
     /* If A is 0 and B is 0, do nothing and stay in State 1
        If A is 1 and B is 0, add 1 to main counter and go to State 2
        If A is 0 and B is 1, subtract 1 to main counter and go to State 4
        If A is 1 and B is 1, do nothing to main counter but add 1 to error counter and go to state 3 */

     if (channelAState && !channelBState)
     {
        count++;
        state = state2;
     }
     /* else ....  lots of code goes here */
     break; /* don't forget break at the end of each case! */
     /* other cases follow */
  }
}


