Need help getting my Arduino mega to read serial properly.

Hey guys I’m trying to make a dashboard with an Arduino Mega that works with Simtools and I can’t seem to get it to work.
Now the problem is I open the serial monitor I can type in S000R000T000F000G000
and it will work I will get an output but it only works once and then i have to type it in 19-20 times for it to output again,

And for testing purposes I’m using a servo that is reading the Fuel Value.

Any help would be much appreciated thanks.

I have setup Simtools to output as so S000R000T000F000G000 so a speed value of 10 would be S010R000T000F000G000 to a max of 255.

#include <Servo.h>

int Speed = 000;
int Rpm = 000;
int Turbo = 000;
int Fuel = 000;
int Gear = 000;
int SpeedGameDash = 0;
int bufferArray[20];
Servo turboservo;


void setup()
{
  Serial.begin(19200);
  pinMode(22, OUTPUT);
  turboservo.attach(22);
  turboservo.write(0);
}

void loop(){
//****************************** READ DATA FROM SERIAL ******************************
  ReadData();
}


void ReadData(){
    if (Serial.available() == 20) { //if 20 bits available in the Serial buffer...
    int i;
    for (i=0; i<=20; i=i+1) { // read and label each byte.
    bufferArray[i] = Serial.read();
    }
    if (bufferArray[0] == 'S'){
        Speed = ((bufferArray[1]-48)*100) + ((bufferArray[2]-48)*10) + // Take values 1-3.
        ((bufferArray[3]-48)*1);
        Serial.print("You have set the Speed to a Value of:");
        Serial.println(Speed);
    }
    if (bufferArray[4] == 'R'){
        Rpm = ((bufferArray[5]-48)*100) + ((bufferArray[6]-48)*10) + // Take values 1-3.
        ((bufferArray[7]-48)*1);
        Serial.print("You have set the Rpm to a Value of:");
        Serial.println(Rpm);
    }
    if (bufferArray[8] == 'T'){
        Turbo = ((bufferArray[9]-48)*100) + ((bufferArray[10]-48)*10) + // Take values 1-3.
        ((bufferArray[11]-48)*1);
        Serial.print("You have set the Turbo to a Value of:");
        Serial.println(Turbo);
    }
    if (bufferArray[12] == 'F'){
        Fuel = ((bufferArray[13]-48)*100) + ((bufferArray[14]-48)*10) + // Take values 1-3.
        ((bufferArray[15]-48)*1);
        Serial.print("You have set the Fuel to a Value of:");
        Serial.println(Fuel);
    }
    if (bufferArray[16] == 'G'){
        Gear = ((bufferArray[17]-48)*100) + ((bufferArray[18]-48)*10) + // Take values 1-3.
        ((bufferArray[19]-48)*1);
        Serial.print("You have set the Gear to a Value of:");
        Serial.println(Gear);
    }
    }
}

This line:if (Serial.available() == 20) This only fires if there are EXACTLY 20 characters. If you miss one, then you don't hit 20 and you can go past it to 21.

Don't wait until the buffer is full. Try to recognise the start condition (carriage-return-S) and then start recognising the rest of the string, letting your program run while you're waiting for the next character to arrive. Use a state machine to keep track of what characters you've seen and where you are up to.

If the next character doesn't match the expected input, reset back to waiting for the start sequence again, discarding any characters that don't match.

Fantastic, i looked up state machines and it does exactly what i want

#include <Servo.h>

typedef enum {  NONE, GOT_S, GOT_R, GOT_T, GOT_F, GOT_G } states;

states state = NONE;

unsigned int currentValue;
Servo turboservo;

void setup ()
{
  Serial.begin (115200);
  state = NONE;
  pinMode(22, OUTPUT);
  turboservo.attach(22);
  turboservo.write(0);
} 

void processSpeed (const unsigned int value)
{
  //Print out the Speed value 
  Serial.print ("Speed = ");
  Serial.println (value);
}


void processRPM (const unsigned int value)
{
  //Print out the RPM value 
  Serial.print ("RPM = ");
  Serial.println (value);
}

void processTurbo (const unsigned int value)
{
  //Print out the Turbo value
  Serial.print ("Turbo = ");
  Serial.println (value); 
  turboservo.write(value);
}

void processFuel (const unsigned int value)
{
  //Print out the Fuel value
  Serial.print ("Fuel = ");
  Serial.println (value);
}

void processGear (const unsigned int value)
{
  //Print out the Gear value
  Serial.print ("Gear = ");
  Serial.println (value);  
}

void handlePreviousState ()
{
  switch (state)
  {
  case GOT_S:
    processSpeed (currentValue);
    break;
  case GOT_R:
    processRPM (currentValue);
    break;
  case GOT_T:
    processTurbo (currentValue);
    break;
  case GOT_F:
    processFuel (currentValue);
    break;
  case GOT_G:
    processGear (currentValue);
    break;
  } 

  currentValue = 0; 
} 

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
    switch (c)
    {
    case 'S':
      state = GOT_S;
      break;
    case 'R':
      state = GOT_R;
      break;
    case 'T':
      state = GOT_T;
      break;
    case 'F':
      state = GOT_F;
      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 ());


  
}  // end of loop

The examples in serial input basics may be useful

...R

@Draknoid I was able to use your code to get serial reading the numbers coming in from Assetto Corsa via Simtools. I'm trying to understand exactly what you we're attempting, as my project needs are a little different. I'm building a fan control based on speed. Your code is the furthest I've come to getting the speed value out. Do you have a schematic or drawing of your circuit/setup?

Thanks, Rob

EDIT:Oh I forgot, you mentioned your Simtools setup to output S000R000T000F000G000 Can you provide a screenshot of your Simtools output settings? I'm a totaly n00b (two days in) when it comes to Simtools.