HandleRunningState() Was Not Declared in this scope

I have been experimenting and adding to my state machine additional states to handle other functions and all has been relatively good with adding additional states as the need arises. At one time, I was having difficulties with persistent errors when compiling,, but thought I had working out a couple of sequences that seemed to needed to be done in order so as not to get them. (// when adding new states, add the "HandlexxxState,,", then compile,and then add the "case" I don't know if it was dumb luck doing it that way, but it seemed to work.

But now, I am getting a constant error "HandleRunningState was not declared in this scope ( which is in the switch state layout in the void loop )

Is there a specific order or correct method that I'm not using ? Is there a structure or layout that I'm missing?

As I said, I had them all working before, but since I've added some new ones I can't clear this error.

I can see nothing wrong with the code that you have not posted

:slight_smile: touche! but in my defense I was thinking that I am not aware of some fundamental method of laying out the functions. Saving you the pain of wading through the code.
However, I suppose there is nothing like looking under the hood and wiggling stuff to see if works!

/*version5
  - replacing delays in ALARM loop with timers
  - adding in Lowlight function trigger
  need to figure out how to start and maintain running when triggered by temp ( possible timeout?)
  and/or photocell (maintaining running when output high??)
  -added pre & post crank states to fix cranking on and break out functions.
  

*/
// system states
#define STOPPED   0
#define STARTING  1
#define PreCranking 2
#define CRANKING  3
#define PostCranking 4
#define RUNNING   5
#define ALARM     6
#define LOWLIGHT  7
#define LOWTEMP   8

#define Glow_Plug_On  10000 // 10 secs for testing
#define RUNNING_TIMEOUT 12000 // 12 secs for testing
#define NumStartAttempts 3 //sets the limit of attempts to try starting

const int ledPin = 13;          //red LED
const int starterPin = 12;      //green LED to represent turn on starter motor,
const int onPin = 11;           //yellow LED, represent ACC & IGN ON
const int alternatorPin = 10;   //yellow button, used to simulate running status HIGH
int glowPlugPin = 4;            // Pin 4 to represent glow plug
int start_trigger = 2;          // trigger to start the process
int state = STOPPED;            // master variable for the state machine

// for starter functions
unsigned long StartedTime = 0; // initialize the time when the engine was started
unsigned long Running_Time = 0; // don't know what this is for and where its used, might not be needed
int StarterOnTime = 5000 ;      // the length of time we want to crank(turn on) the starter motor
int StarterOffTime = 100;
int StarterTries = 0;           // initialize number of times the starter has been engaged
long int CrankStarterTime;

// for alarm LED blinking:
int ledState = LOW;  // ledState used to set the LED
unsigned long previousMillis = 0;        // will store last time LED was updated
const long interval = 1000;           // interval at which to blink (milliseconds)

//for photocell
int LDR = 1;                  //analog pin to which LDR is connected, here we set it to 0 so it means A1
int LDRValue = 0;             //that's a variable to store LDR values
int light_sensitivity = 570;  //This is the approx value of light surrounding LDR

void setup()
{
  pinMode(onPin, OUTPUT);             //pin 11 used for ign and acc
  pinMode(starterPin, OUTPUT);        //pin 12 used to turn on the starter motor
  pinMode(ledPin, OUTPUT);            //pin13
  pinMode(alternatorPin, INPUT);      //pin 10 alternator for Running status when HIGH
  pinMode(glowPlugPin, OUTPUT) ;      //pin 4 used for glow plug
  pinMode(start_trigger, INPUT);      //pin 2 for start_trigger.In future to provide trigger from Photocell and/or Temp Sensor
  //pinMode(10, INPUT);                 //alternator for Running status when HIGH
  Stop();                   // Make sure everything is set correctly
  Serial.begin(9600);


}

void loop()
{

  switch (state) // when adding new states, add the "HandlexxxState,,", then compile,and then add the "case"
  {
    case STOPPED:
      HandleStoppedState();
      break;
    case STARTING:
      HandleStartingState();
      break;
    case PreCranking:
      preCrankingState();
      break;
    case RUNNING:
      HandleRunningState();
      break;
    case CRANKING:
      HandleCrankingState();
      break;


    case ALARM:
      HandleAlarmState();
      break;
    case LOWTEMP:
      HandleLowTempState();
      break;
    case LOWLIGHT:
      HandleLowLightState();
      break;
    case PostCranking:
      PostCrankingFailure();
      break;
    default:
      Serial.print("Unknown State: ");
      Serial.println(state);
      Stop(); // Should never get here
      break;
  }

}

void Stop()
{
  digitalWrite(starterPin, LOW);
  digitalWrite(onPin, LOW);
  digitalWrite(glowPlugPin, LOW);
  state = STOPPED;

}

void HandleStartingState()
{
  if (digitalRead(alternatorPin) == HIGH)
  {
    Serial.println("Abort cranking, engine is already running  ");
    StartedTime = millis();
    Stop(); // Don't crank the engine - it's already running
  }
  else
  {
    digitalWrite(onPin, HIGH);
    Serial.println("ignition & acc ON");
    delay (8000);
    digitalWrite(glowPlugPin, HIGH);
    Serial.println("Glow Plug ON");
    delay (Glow_Plug_On);
    {
      state = CRANKING;

    }
  }
}


void HandleStoppedState()
{
  LDRValue = analogRead(LDR);
  //Serial.println(LDRValue);
  if ((LDRValue < light_sensitivity) || (digitalRead(start_trigger) == HIGH))
  {
    StartedTime = millis();
    digitalWrite(starterPin, LOW);
    digitalWrite(onPin, HIGH);
    state = STARTING;

  }

}
void preCrankingState()
{ CrankStarterTime = millis ();
  if (StarterTries < NumStartAttempts)
  { StarterTries = StarterTries + 1;
    state = CRANKING;

  }
  else {
    Serial.print("Starting Attempts exceeded  ");
    Serial.println(StarterTries);
    digitalWrite(starterPin, LOW);
    digitalWrite(glowPlugPin, LOW);
    digitalWrite(onPin, LOW);
    state = ALARM;
  }
}
void HandleCrankingState()
{

  { //keep trying to start

    if (digitalRead(alternatorPin) != HIGH)
    {
      if (millis() - CrankStarterTime < StarterOnTime)
      { digitalWrite (starterPin, HIGH);
      }

      else if (digitalRead(alternatorPin) == HIGH)
      {
        digitalWrite(starterPin, LOW);
        Serial.println("started now");
        StartedTime = millis();
        state = RUNNING;
      }
      else
      {
        long int StarterOffNow = millis ();
        state = PostCranking;
      }
    }
  }
  void PostCrankingFailure()
  {
    if (millis() - StarterOffNow < StarterOffTime)
    { digitalWrite(starterPin, LOW);
    }
    else {
      state = PreCrankingState;
    }
  }
  void HandleRunningState()
  {
    digitalWrite(glowPlugPin, LOW);
    if (millis() - StartedTime >= RUNNING_TIMEOUT)// || (start_trigger = LOW)) tried adding a condition to keep it running if the start trigger was still active
    {
      Serial.println("Running Timeout");
      Stop();
    }
  }
  void HandleAlarmState()
  {
    if (digitalRead(start_trigger) != HIGH)
    { Serial.println("In Alarm until reset");
      unsigned long currentMillis = millis();
      if (currentMillis - previousMillis >= interval)
      {
        // save the last time you blinked the LED
        previousMillis = currentMillis;
        // if the LED is off turn it on and vice-versa:
        if (ledState == LOW)
        {
          ledState = HIGH;
        }
        else {
          ledState = LOW;
        }
        // set the LED with the ledState of the variable:
        digitalWrite(ledPin, ledState);
      }

    }
    else
    {
      digitalWrite(ledPin, LOW);
      StarterTries = 0; //reset starter count
      state = STARTING;

    }
  }
  void HandleLowLightState()
  {
    /*
      {

        Serial.println("low light levels,, triggering start_trigger");
        start_trigger = HIGH;
        state = STARTING;

      }
      else
      {
        state = STOPPED;
      }
    */
  }
  void HandleLowTempState()
  {

  }

You have a superfluous opening brace at the beginning of HandleCrankingState. It's confusing the compiler.

I Auto Formatted your code in the IDE and could immediately see that functions towards the end of your program do not start on the left margin. This is a clue that somewhere above where this happens in the code there is at least one missing } at the end of a function or too many { somewhere

Try Auto Format for yourself. Where does the HandleCrankingState() function end ? Come to that, why does it start with two { ?

wildbill: You have a superfluous opening brace at the beginning of HandleCrankingState. It's confusing the compiler.

see that now! tyvm

UKHeliBob: I Auto Formatted your code in the IDE and could immediately see that functions towards the end of your program do not start on the left margin. This is a clue that somewhere above where this happens in the code there is at least one missing } at the end of a function or too many { somewhere

Try Auto Format for yourself. Where does the HandleCrankingState() function end ? Come to that, why does it start with two { ?

see that now too,, tyty.

I have been staring at this for the last 2 days and never even thought to meticulously go through it manually looking for careless and simple formatting errors like you have both quickly discovered. I guess I couldn't see the forest for the trees!!

I have corrected them all (and a few more that popped up once I corrected these) and it finally compiled successfully. Now,, to see if it actually works!!

Thank you both for your quick replies and insight.

I'll probably be back with more problems/questions! TY

now the issue I have is that it doesn't react to the alternatorPin going HIGH ( which should stop the cranking process, and go to RUNNING and also detect if its already running prior to the preCranking event). I added a serial print into HandleCrankingState and see that it does recognize the alternatorPin goes HIGH (1) during the cranking state and starting attempt. But it still continues the cranking, goes to postcranking to stop, then back to another preCranking to increment then into Cranking for the on duration until attempts are exceeded, then Alarm.

So all that seems to work and I do see the input value change to HIGH (1), but it doesn't respond to it. Have I got to many "If " decisions that are confusing the logic ?

have to post code separate. I got an error that i exceeded 9000 characters, and had to wait 5 minutes

/*version5
  - replacing delays in ALARM loop with timers
  - adding in Lowlight function trigger
  need to figure out how to start and maintain running when triggered by temp ( possible timeout?)
  and/or photocell (maintaining running when output high??)
  -added pre & post crank states to fix cranking on and break out functions.
*version6
-its not reacting to alternatorPin == HIGH to respond when its running

*/
// system states
#define STOPPED   0
#define STARTING  1
#define PreCranking 2
#define CRANKING  3
#define PostCranking 4
#define RUNNING   5
#define ALARM     6
#define LOWLIGHT  7
#define LOWTEMP   8

#define Glow_Plug_On  10000 // 10 secs for testing
#define RUNNING_TIMEOUT 12000 // 12 secs for testing
#define NumStartAttempts 3 //sets the limit of attempts to try starting

const int ledPin = 13;          //red LED
const int starterPin = 12;      //green LED to represent turn on starter motor,
const int onPin = 11;           //yellow LED, represent ACC & IGN ON
const int alternatorPin = 10;   //yellow button, used to simulate running status HIGH
int glowPlugPin = 4;            // Pin 4 to represent glow plug
int start_trigger = 2;          // trigger to start the process
int state = STOPPED;            // master variable for the state machine

// for starter functions
unsigned long StartedTime = 0; // initialize the time when the engine was started
unsigned long Running_Time = 0; // don't know what this is for and where its used, might not be needed
int StarterOnTime = 15000 ;      // the length of time we want to crank(turn on) the starter motor
int StarterOffTime = 1500;       // pause time between starts
int StarterTries = 0;           // initialize number of times the starter has been engaged
long int CrankStarterTime;
long int StarterOffNow;

// for alarm LED blinking:
int ledState = LOW;  // ledState used to set the LED
unsigned long previousMillis = 0;        // will store last time LED was updated
const long interval = 1000;           // interval at which to blink (milliseconds)

//for photocell
int LDR = 1;                  //analog pin to which LDR is connected, here we set it to 0 so it means A1
int LDRValue = 0;             //that's a variable to store LDR values
int light_sensitivity = 570;  //This is the approx value of light surrounding LDR

void setup()
{
  pinMode(onPin, OUTPUT);             //pin 11 used for ign and acc
  pinMode(starterPin, OUTPUT);        //pin 12 used to turn on the starter motor
  pinMode(ledPin, OUTPUT);            //pin13
  pinMode(alternatorPin, INPUT);      //pin 10 alternator for Running status when HIGH
  pinMode(glowPlugPin, OUTPUT) ;      //pin 4 used for glow plug
  pinMode(start_trigger, INPUT);      //pin 2 for start_trigger.In future to provide trigger from Photocell and/or Temp Sensor
  //pinMode(10, INPUT);                 //alternator for Running status when HIGH
  Stop();                   // Make sure everything is set correctly
  Serial.begin(9600);


}

void loop()
{

  switch (state) // when adding new states,add the "#define", then add the "HandlexxxState,,", then compile,and then add the "case"
  {
    case STOPPED:
      HandleStoppedState();
      break;
    case STARTING:
      HandleStartingState();
      break;
    case PreCranking:
      preCrankingState();
      break;
    case CRANKING:
      HandleCrankingState();
      break;
    case PostCranking:
      PostCrankingFailure();
      break;
    case RUNNING:
      HandleRunningState();
      break;
    case ALARM:
      HandleAlarmState();
      break;
    case LOWLIGHT:
      HandleLowLightState();
      break;
    case LOWTEMP:
      HandleLowTempState();
      break;


    default:
      Serial.print("Unknown State: ");
      Serial.println(state);
      Stop(); // Should never get here
      break;
  }

}

void Stop()
{
  digitalWrite(starterPin, LOW);
  digitalWrite(onPin, LOW);
  digitalWrite(glowPlugPin, LOW);
  state = STOPPED;

}
void HandleStoppedState()
{ LDRValue = analogRead(LDR);
  //Serial.println(LDRValue);
  if ((LDRValue < light_sensitivity) || (digitalRead(start_trigger) == HIGH))
  {
    StartedTime = millis();
    digitalWrite(starterPin, LOW);
    digitalWrite(onPin, HIGH);
    state = STARTING;

  }

}
void HandleStartingState()
{
  if (digitalRead(alternatorPin) == HIGH)
  {
    Serial.println("Abort cranking, engine is already running  ");
    StartedTime = millis();
    Stop(); // Don't crank the engine - it's already running
  }
  else
  {
    digitalWrite(onPin, HIGH);
    Serial.println("ignition & acc ON");
    delay (8000);
    digitalWrite(glowPlugPin, HIGH);
    Serial.println("Glow Plug ON");
    delay (Glow_Plug_On);
    {
      state = PreCranking;

    }
  }
}



void preCrankingState()
/*pre cranking state can keep track of number of attempts and note when this attempt started.
  What you need is indeed to set startCrankingTime to millis, but not in the cranking state.
  Set it in whatever sets the state to cranking. Then it stays fixed while cranking, time passes and you can check in cranking state whether you exceeded the timeout or started the engine.
  That's why I suggested adding a pre cranking state because you need to manage the number of starting attempts and set the startCrankingTime before you get into cranking state.
*/
{
  CrankStarterTime = millis ();

  if (StarterTries < NumStartAttempts)
  { if (digitalRead(alternatorPin) == LOW)
    {
      StarterTries = StarterTries + 1;
      state = CRANKING;
    }

    else if (digitalRead(alternatorPin) == HIGH)
  {
    state = RUNNING;
  }
}
else {
  Serial.print("Starting Attempts exceeded  ");
    Serial.println(StarterTries);
    digitalWrite(starterPin, LOW);
    digitalWrite(glowPlugPin, LOW);
    digitalWrite(onPin, LOW);
    state = ALARM;
  }
}
void HandleCrankingState()
/*Cranking state just cranks until the engine starts or millis tells you that you've exceeded the time allowed.
  If the engine started, you're running; otherwise you note the time and go to the post state.
  keep trying to start*/
{
  if (digitalRead(alternatorPin) == LOW)
  {
    if (millis() - CrankStarterTime < StarterOnTime)
    { digitalWrite (starterPin, HIGH);
      Serial.println(" starting attempt #");
      Serial.println(StarterTries);
      int val = digitalRead(alternatorPin); // assign the pinstate value to val
      Serial.println("alternatorPin value");
      Serial.println(val);                  // print out the state of the alternatorPin input value to verify if it is being read but not responding
    }

    else if (digitalRead(alternatorPin) == HIGH)
    {
      digitalWrite(starterPin, LOW);
      Serial.println("started now");
      StartedTime = millis();
      state = RUNNING;
    }
    else
    {
      StarterOffNow = millis ();
      state = PostCranking;
    }
  }
}

void PostCrankingFailure()
/*postCrankingfailure state tracks the time until you're ready to crank again and then puts you back in pre cranking.
   It's only purpose is to stop one cranking attempt from blending into the next.
   Just as you give the engine a rest between attempts when you do it manually.

*/
{
  if (millis() - StarterOffNow < StarterOffTime)
  { digitalWrite(starterPin, LOW);
  }
  else
  {
    state = PreCranking;
  }
}
void HandleRunningState()
{
  digitalWrite(glowPlugPin, LOW);
  if (millis() - StartedTime >= RUNNING_TIMEOUT)// || (start_trigger = LOW)) tried adding a condition to keep it running if the start trigger was still active
  {
    Serial.println("Running Timeout");
    Stop();
  }
}
void HandleAlarmState()
{
  if (digitalRead(start_trigger) != HIGH)
  { Serial.println("In Alarm until reset");
    unsigned long currentMillis = millis();
    if (currentMillis - previousMillis >= interval)
    {
      // save the last time you blinked the LED
      previousMillis = currentMillis;
      // if the LED is off turn it on and vice-versa:
      if (ledState == LOW)
      {
        ledState = HIGH;
      }
      else {
        ledState = LOW;
      }
      // set the LED with the ledState of the variable:
      digitalWrite(ledPin, ledState);
    }

  }
  else
  {
    digitalWrite(ledPin, LOW);
    StarterTries = 0; //reset starter count
    state = STARTING;

  }
}
void HandleLowLightState()
{

}
void HandleLowTempState()
{

}

The else that sets state to running should be associated with this if:

  if (digitalRead(alternatorPin) == LOW)
  {

The way you have it, it’s the else for the check to see if you should keep cranking due to time. Also, there will then be no need to check the alternator status again in the else. If it isn’t LOW, it must be HIGH.

i'm not to sure I completely get it yet, so bear with me, but in which state are you talking about? In PreCrank or Cranking ? I recognize that I'm checking in both states,, which might be confusing me and the logic. I think you originally told me to check it in Cranking only, so I might have muddled that part up.

so i took out any alternator status checking from PreCrank and finally understood what you were pointing out.
So here is what I think you were trying to get me to understand ( it must be right because it works exactly the way I was expecting it to !)

void HandleCrankingState()
/*Cranking state just cranks until the engine starts or millis tells you that you've exceeded the time allowed.
  If the engine started, you're running; otherwise you note the time and go to the post state.
  keep trying to start*/
{
  if (digitalRead(alternatorPin) == LOW)  // if no Running signal then start cranking
  {
    if (millis() - CrankStarterTime < StarterOnTime)
    { digitalWrite (starterPin, HIGH);
      Serial.println(" starting attempt #");
      Serial.println(StarterTries);
      int val = digitalRead(alternatorPin); // assign the pinstate value to val
      Serial.println("alternatorPin value");
      Serial.println(val);                  // print out the state of the alternatorPin input value to verify if it is being read but not responding
    }
    else                        // once starter on timer expires, then note the time and go to post cranking
    {
      StarterOffNow = millis ();
      state = PostCranking;
    }
  }

  else                      // the Running signal must be HIGH then, so it is now go to Running state
  {
    digitalWrite(starterPin, LOW);
    Serial.println("started now");
    StartedTime = millis();
    state = RUNNING;
  }

}

That's it. Glad to hear it's working.

yes,, thanks to your insight! Now,, onto the temp and photocell trigger options. Be prepared for more questions! lol Cheers Rob