return function

I have an if statement buried within a while loop, an if statement, another if statement, another while loop, and a for loop, which is inside a called function. From the first buried if statement is it possible to immediately return to the for loop or to exit to the called function or any specified level of this logic?

Take a 'break'

Always show us your current compete sketch.
Use CTRL T to format the sketch.
Please use code tags.
Use the </> icon in the posting menu.

[code] Paste sketch here. [/code]

https://www.arduino.cc/en/Reference/Break

.

If it's that "deep" it may be time to rethink your logic. Perhaps look at a state machine approach? Have a look for instance here, here or here.

It's a voice menu selection function with timed delay selection periods:

void enterMenu(void)
{
  uint8_t maxOptions = 25;
  uint8_t offset = 4;
  long startWaitTime;  //  do with loop counts instead?
  long firstTouchWaitTime = 1000;
  long secondTouchWaitTime = 500;
  boolean firstTouch = false;
  boolean secondTouch = false;


  playSound(3);  // menu intro
  while (playingSound);  //  wait to start sensing until after sound played.

  for (option = 0; option < maxOptions; option++)
  {
    playSound(offset + option);  //  voice option
    while (playingSound);  //  wait to start sensing until after sound played.

    startWaitTime = millis();
    while (millis() - startWaitTime <= firstTouchWaitTime)
    {
      if (checkADCTouch()) // first touch, then wait for 2nd
      {
        firstTouch = true;
        clearADCTouchStatusArray();
      }

      if (firstTouch)
      {
        firstTouch = false;
        startWaitTime = millis();
        while (millis() - startWaitTime <= secondTouchWaitTime)
        {
          if (checkADCTouch()) // 2nd touch
          {
            clearADCTouchStatusArray();
            secondTouch = true;
            return;  // need to return from the for loop and start the selected routine function.
          }

        }
        // 2nd wait time timed out, go to next menu option.
      }
    }
  }
}

First of all you can use break and continue; break will jump out of a loop (for, while)

for (int cnt=0; cnt<10; cnt++)
{
  ...
  ...
  if (somecondition == true)
  {
    break;
  }
  ...
  ...
}

continue will skip te rest of the loop and go back to the beginning

for (int cnt=0; cnt<10; cnt++)
{
  ...
  ...
  if (somecondition == true)
  {
    continue;
  }
  ...
  ...
}

Further the condition in a for statement can be as complex as you want; most people use something like

for (int cnt=0; cnt<10; cnt++)
{
  ...
  ...
}

With a more complex condition

static bool breakFromLoop = false;
for (int cnt = 0; cnt < 10 && breakFromLoop == false; cnt++)
{
  ...
  ...
  breakFromLoop = somecondition;
  ...
  ...
}

This will complete the current run of the for loop and when the code gets to the beginning, both cnt and breakFromLoop will be evaluated.

perigalacticon:
It's a voice menu selection function with timed delay selection periods:

There MUST be a better way.

Please describe in English (without any code) the process that you want to happen.

...R

Alright I actually have it spelled out in the sketch:

  //  enter menu mode
  //  play menu option
  //  check for touch
  //    while during first time period check for 1st touch.
  //      if no touch then replay option.
  //      if 1st touch then start sensing for second touch in 2nd time period.
  //      while during 2nd time period check for 2nd touch
  //        if no touch detected then skip to next menu option.
  //        if touch during 2nd time period then select the option, leave the menu
  //        loop and start the selected routine.
  //    if end of menu start at beginning.

So really simply just looking for a 'double tap' to select a menu option, if so then then exit the menu and call the function for the option.

A single tap only after the option prompt causes skipping to the next option prompt if no 2nd tap detected for the first option. If no taps at all for the option then repeat the voice prompt for the option.

Thanks for your responses!

perigalacticon:
From the first buried if statement is it possible to immediately return to the for loop or to exit to the called function or any specified level of this logic?

void function() {
  // inside a called function
  for (int i = 0; i < 1; i++) { // and a for loop
    while (true) { // another while loop
      if (true) { // another if statement
        if (true) { // an if statement
          while (true) {
            if (true) { // an if statement buried within a while loop,
              break;
            }  // end if
          }  // end while
 // the break jumps to here        
        }  // end if
      }  // end if
    }  // end while
  }  // end for
}  // end function

There is no easy way to escape more than one level of loop. You can use the 'break;' statement to exit the inner while loop and continue with outer while loop. To exit both levels you would typically set a flag and have a "break;" statement in the outer loop triggered by the flag:

void function() {
  boolean exitflag = false;
  // inside a called function
  for (int i = 0; i < 1; i++) { // and a for loop
    while (true) { // another while loop
      if (true) { // another if statement
        if (true) { // an if statement
          while (true) {
            if (true) { // an if statement buried within a while loop,
              exitflag = true;
              break;
            }  // end if
          }  // end while
          // the break jumps to here
          if (exitflag)
            break;
        }  // end if
      }  // end if
    }  // end while
    // Second break jumps to here
  }  // end for
}  // end function

perigalacticon:
Alright I actually have it spelled out in the sketch:

I don't recall seeing that in the code in Reply #5 :slight_smile: - perhaps you can see the value of posting a complete program!

Also, I don't think that description properly reflects the code in Reply #5 - it does not deal with the FOR menu options.

Leaving aside the question of the FOR, the rest of the requirement is crying out for conversion to a "state machine" system which will allow those WHILEs to become IFs

You are transitioning through 3 states for each menu

  • waiting for touchA
  • waiting for touchB
  • finished or timed-out

What I can't get my head around is your use of the FOR OPTIONs. If there are are several options shouldn't the user be able to select any one of them without having to go through them all one after the other? If you post a diagram showing how it will look to the user it will probably make the whole thing clearer. A very simple pencil drawing should be fine.

...R

Hate to say it, but this is one of the canonical places a goto might work.

And in goto's defense, C's tightening of the requirement to be limited to inside a function really constrains the amount of damage a goto can do.

I worked on a GWBasic program once that as its first statement goto'd to the end of the program!

I'm with Robin using a statemachine. The below can act as a framework

First you need to define the states and declare a variable for the state

#define ST_PLAY 0           // play voice
#define ST_WAITPLAY 1       // wait for play to be completed
#define ST_WAIT1 2          // wait for first tap
#define ST_WAIT2 3          // wait for second tap
#define ST_EXEC 4           // execute selected option

byte currentState = ST_PLAY;

...
...
void setup()
{
  ...
  ...
}

And next you can implement the statemachine in e.g. loop().

void loop()
{
  static byte currentOption = 0;
  unsigned long startWaitTime;  //  do with loop counts instead?
  unsigned long firstTouchWaitTime = 1000;
  unsigned long secondTouchWaitTime = 500;

  switch (currentState)
  {
    case ST_PLAY:
      playSound(currentOption);
      // wait for sound to finish
      currentState = ST_WAITPLAY;
      break;
    case ST_WAITPLAY:
      // if the sound is finished, check for 'tap'
      if (playingsound == false)
      {
        currentState = ST_WAIT1;
        startWaitTime = millis();
      }
      break;
    case ST_WAIT1:
      // if there was a 'tap', check for second 'tap'
      if (checkADCTouch())
      {
        currentState = ST_WAIT2;
        startWaitTime = millis();
      }
      // if there was no 'tap' within given time, play the voice again
      if (millis() - startWaitTime >= firstTouchWaitTime)
      {
        currentState = ST_PLAY;
      }
      break;
    case ST_WAIT2:
      // if there was a 'tap', execute selected menu option
      if (checkADCTouch())
      {
        currentState = ST_EXEC;
        startWaitTime = millis();
      }
      // if there was no second 'tap' within given time, play next menu voice
      if (millis() - startWaitTime >= secondTouchWaitTime)
      {
        currentOption++;
        if (currentOption == 25)
        {
          currentOption = 0;
        }
        currentState = ST_PLAY;
      }
      break;
    case ST_EXEC:
      // do whatever needs to be done
      ...
      ...

      // when finished, play the voice for the first option
      currentOption = 0;
      currentState = ST_PLAY;
      break;
  }
}

Note that the comments for the state change describe the condition and the next state. So a comment like

      // when finished, play the voice for the first option

does not mean that the voice is played at that point but that the next state is the state that plays the voice.

With some hacks (I don't have your hardware and libraries and your code is not complete), it compiles. But I did not test.

Wow thanks you guys! It's a toy that will be activated by capacitive touch, and the outputs are LEDs and sound though a speaker. There will be several cap touch channels available for inputs but the menu options list will likely be more than 10, so it is simpler to present the options sequentially.

perigalacticon:
Wow thanks you guys! It's a toy that will be activated by capacitive touch, and the outputs are LEDs and sound though a speaker. There will be several cap touch channels available for inputs but the menu options list will likely be more than 10, so it is simpler to present the options sequentially.

I remain to be convinced :slight_smile:
Simpler for whom?

Anyway, assuming you do want to do it sequentially then I would treat each of the options as a separate state in a style similar to what @sterretje has suggested for the selection within each option.

That way there will be nothing inside anything else that needs to be exited.

...R