Nesting vs Flow

I feel a little stupid here. I have been trying, for a long time, to kill the process that might be in and start over at the beginning. I simply added IF this happens, loop();. It restarted! Can it be that simple? Well not exactly.

This brings me to a question. It is hard to put into words so I hope that you get what I am trying to say.

If I meander from one function to the next, to the next, back to one and so on, does all of the history stay with it? If I finish a function, I go back to the one that called it. How far will it go back? Does the program hold all of that history in memory? Does the program just flow along or is everything nested endlessly?

Does it just flow? loop->keyPadFunction->mainMenu->manualMode->manualStep->mainMenu->return->loop->onStart->moveToStation->AllStop->loop and so on. Or is it nested? (((((loop) keyPadFunction)mainMenu)manualMode)manualStep)---- ^ | | V | (mainMenu)return | |

| |

I’m lost.

The stack space is used for this, each function call is "pushed" onto the stack, when it returns it is "popped" from the stack. As the callee of a called function hasn't returned its data is still on the stack.

So the memory position ( in the stack ) before a function is the stack space for the function that called it, this may include saved register states between calls.

The stack actually starts at the end of RAM and grows backwards, just switch the meanings of before and after and you're fine :)

The recursion limit is based on memory exhaustion, AVR's have the bonus of not having program space in ram so you can recursively call small functions many times before a considerable amount of memory is used.

[quote author=Asa Herring link=topic=206419.msg1518583#msg1518583 date=1387861888] I feel a little stupid here. I have been trying, for a long time, to kill the process that might be in and start over at the beginning. I simply added IF this happens, loop();. It restarted! Can it be that simple? [/quote]

Calling loop() from within itself is a bad idea. It's called recursion, and is defined as calling a function from within the function you're calling. It has its uses, but it has to be carefully planned. One thing it needs is an 'escape', or a way to end the current iteration of the function. If it doesn't have this, it will continue to call itself, and each call will cause the stack to be used for (a) information that is needed for the return from the function, and (b) any variables declared within the function. Eventually, your program will run out of room in RAM, and will, in all likelihood, do some seemingly random things, none of which you planned on doing.

You can start loop() over again by doing a return. That will bring you back to the statement after the one that called loop() in the first place, and which time THAT bit of codde will simply call loop() again.

That being said, it is almost always a matter of structuring your program, to avoid such a thing. Unless you are writing your own setup() or main(), you should use loop() as intended. It should keep running, and within that loop(), you should be using flags or status values to determine what blocks of code are to be run.

For example, suppose you have some things to do when you first enter loop(); things like setting up a menu and allowing the user to choose a course of action. Something like this (pseudocode)is appropriate:

void loop() {
   if not menuDone {
      operation = getMenuChoice()
      menuDone = true;
   }
   if operation == taskA {
      taskA()
      taskA  = noTask
      menuDone = false
   }
   if operation = taskB {
      taskB()
      operation = noTask
      menuDone = false
   }
}      // end of loop()

In this code, the assumption is that the function getMenuChoice initializes and shows a menu, accepts user input, and returns with a value that indicates what has to be done next. When the task is done, operation is reset to indicate we are through doing a task, and menuDone is set to allow us to enter the if statement that calls getMenuChoice() again.

This is just one example of structuring a program, and it will not fit all programs you want to write. The idea is to figure out what needs to be done in each pass through loop(), and to direct the traffic to make sure it does what it should be doing.

How can I kill the stack?

In short you can go as “deep” as you like with functions calling functions calling functions, eventually most of them will return and the CPU will know where to return to because that information is on the stack (a special part of RAM memory). This works until you have too many nested calls and the stack overflows into data memory, at which point things go south pretty quick.

This almost never happens unless you are using recursion where a function calls itself, eg

loop () {
   myfunc(0);
  Serial.println(x);  // should print 100
}

myfunc (int x) {
    x++;
   if (x < 100)
       myfunc(x);
}

this will cause 100 “blocks” of state information to be saved (pushed) on the stack, then when x reaches 100 they will all be popped from the stack in what will essentially be 100 returns in a row. On a small CPU pushing this much onto the stack could easily cause it to crash.

BTW you have recursion in your example

loop->keyPadFunction->mainMenu->manualMode->manualStep->mainMenu->return-

If they are supposed to be functions then mainMenu calls itself, and of course the call to loop() is recursion as well.


Rob

I have talked about an ALL STOP. If the mechanical stuff goes wrong. I look for a sensor change or a certain key to be pressed ... at any time…any place. When I want to start back at the beginning, what do I do?

Right now, I look for the key that I want and access the menu structure to let the user decide how to rectify the fix that he/she/I am in and what to do about it. Maybe I need to move the carriage a number of steps, then move a little more in push button manual mode to get some information. Finally, go home and start over.

How do I just start over without the stack?

A state machine would be appropriate here. You can move deeply into a menu from the user's point of view, but from the code point of view just be in a simple loop.

http://gammon.com.au/statemachine

Implementing an "ALL STOP" then is as simple as changing the state back to the initial state.

How can I kill the stack?

Quite simply, you almost never need to do this. There are ways, exceptions is one of them (not available on the Arduino) and also non-local goto, however I recommend the state machine.

[quote author=Nick Gammon link=topic=206419.msg1518625#msg1518625 date=1387866503] Quite simply, you almost never need to do this. There are ways, exceptions is one of them (not available on the Arduino) and also non-local goto, however I recommend the state machine. [/quote]

Exceptions are actually quite the opposite. They provide a safe mechanism to recover from an error/loss of state by unwinding the stack to the point of the first encountered exception handler. If it can resolve the error, the stack is intact and ready to go. If it cannot, the exception is re-thrown and the unwinding continues to the next handler.

I use states quite a bit for using the same button pushes in different menus but I don’t see how I would get rid of the history/stack when I start over.

I am also ignorant of exception handling.

pYro_65: Exceptions are actually quite the opposite. They provide a safe mechanism to recover from an error/loss of state by unwinding the stack ...

Unwinding the stack, and killing the stack, seem the same to me (in a sense). You are discarding stack entries.

[quote author=Nick Gammon link=topic=206419.msg1518645#msg1518645 date=1387868514]

pYro_65: Exceptions are actually quite the opposite. They provide a safe mechanism to recover from an error/loss of state by unwinding the stack ...

Unwinding the stack, and killing the stack, seem the same to me (in a sense). You are discarding stack entries. [/quote]

Its not discarding it at all. The purpose of stack unwinding is to call the destructors of the objects that reside in the stack, allowing them to finish and free their memory and so on.

Granted. Exceptions are a cleaner way than a non-local goto.

Did I mention that I don't like goto?

So what do I do and how can I do it? as bad as it is, would a GoTo fit the bill?

Post your code?

Since you agree state machines are the way to go.

I posted most everything here: http://forum.arduino.cc/index.php?topic=206355.new;topicseen#new

[quote author=Asa Herring link=topic=206419.msg1518658#msg1518658 date=1387869550] I posted most everything here: http://forum.arduino.cc/index.php?topic=206355.new;topicseen#new [/quote]

The operative word here is 'most', and that thread does not even have 'most' of the code. It has loop() only, and is missing global variables, defines, includes, if there are any, as well as any of the functions called from loop(), and setup(). Yes, you point to other code in that same posting, but by your own admission, that code has changed.

Additionally, there really is no reason I can think of, that anyone trying to help should want to wander all over the place gathering up your snippets, combining them, trying to guess what might have changed, loading it into an IDE, and attempting to see what might be wrong, and/or how to advise you to solve YOUR problem.

If you want advice, please post your entire code here, in this thread. There are people here who are really trying to help you, but you are not making it easy.

(Updated in next post)

I am sorry. I am a little ashamed to post code for an expert to look at. Now I have including it.

I didn’t think that you would want to sift through my mess. I was hoping that there was a function that would just kill the stack. As bad as it is, this code works mostly as I want it to. It needs a little polishing since I have move on, in some places before completely finishing up each area.

I am just looking to know what to do if the hardware side goes awry.

Again, if the step motor is moving the carriage left, the program looks for a ‘*’. If so I go to allStop() where I look for ‘#’ I need to Start over. If I DO just go back to loop(the wrong way), it appears to work great except that it restarts and runs great until it is about to started over the second time. At that point it does not put text on the screen and waits for a key press. If I do the key press, all appears to be great but it doesn’t time out to move back to restart automatically.

http://asaherring.com/arduino/WorkingCode11/WorkingCode11.txt

You missed a crucial part of lar3ry's advice:

please post your entire code here, in this thread

That means post or attach your code. A link to something stored on another website isn't the same thing. Many people here, myself included, will just ignore it.

[quote author=Asa Herring link=topic=206419.msg1519117#msg1519117 date=1387902004] I didn’t think that you would want to sift through my mess. I was hoping that there was a function that would just kill the stack. As bad as it is, this code works mostly as I want it to. It needs a little polishing since I have move on, in some places before completely finishing up each area. [/quote] OK, without wading through all the function calls, I'll speak on general principles, and I speak to the way I would do it. There are other ways, such as unwinding the stack, but this is what I'd do. Hmm... perhaps this way is what those other posters meant by unwinding the stack.

return is your friend, as is a bool to indicate you want to stop.

If you end up in allStop(), you check for a keypress to indicate a wish to stop. At that point, you should set a boolean variable to indicate that you want to return to loop(), and start over. Then, you should return. This will get you back to the statement after the call to allStop(). Here's a revised check in allStop()...

    if (key)
    {
      in = key;
      if (in == '#')
      {
        keyTime = 0;  
        startover = true;    // declared globally as        bool startover = true;
        return;
      }
    }

Note that a break; would suffice here, as the function ends immediately after the while loop. Now, immediately after each call to allStop(), you place a bit of code...

          allStop();
          if (startover) return;

Each return gets you one function closer to loop. When the returns take you back to a statement in loop(), tyou will continue to process loop(). At this point, you need to use if (startover) or if ( ! startover) to control your program flow such that you only execute the code at the beginning of loop().

To cite an example: Suppose you are in moveToNextStation(), and the user presses the '' key, sending you to allStop(). The use then presses '#', and you set startover and return to the **if(startover) return;* line in moveToNextStation(). So you return. assume you had called moveToNextStation() from showBack(). Your modified code in showBack() would read

  moveToNextStation(stepsToNextStation, DIR);
  if (startup) return;
  inputDigitCount = 0;

so you would return, perhaps to keyPadFunction(). Basically, at every call to a function, that COULD lead to allStop(), you check for startover. In the first part of loop(), you would set startover to false.

While I think of it, you can eliminate the doAnAllStop() function, and replace the calls to it with allStop();

As I say, there may be other was, and they might be easier.