OK, newbie here... please bear with me... searched, and can't find a clear solution
My application goes through several "user setup" screens (40x4 LCD, rotary encoder w/button, and 2 other user buttons), and at any point if the user see's that he's input wrong data, I want to have a "restart" button that will (in essence) "goto" the main program loop... a restart, but without going through all my declarations and setup() sections again, which include onscreen "power-on" message screens, etc.
I know "goto" is to be avoided at ALMOST any cost... or so I read.
I've given up on arduino interrupts for this purpose/project, and the total places in the code where I need to "go look" at the status of this "restart" button are few... maybe 4-5 in total.
(Why hast thou given up on thy glorious Interrupts?? I need button debouncing (and verified "release" before 'doing') and other timers to continue working, along with the fact I use a large LCD, the ISR could happen during an LCD write, and if I try to jump/goto some place that prevents the LCD from properly writing, I could (and have) end up with an onscreen mess.... re-entrant issues.)
Thoughts? ...and thanks!
My application goes through several "user setup" screens (40x4 LCD, rotary encoder w/button, and 2 other user buttons), and at any point if the user see's that he's input wrong data, I want to have a "restart" button that will (in essence) "goto" the main program loop.
A state machine is called for here. You have a series of questions, if they want to "restart" you go back to state 1.
This is getting to be my "hobby horse", but interrupts are a nasty distraction to "newbie" programmers. Interrupts can be - and should almost always be - completely ignored and left to the ambit of certain library routines such as those for keeping time.
In this case, you have been confused by the idea that an interrupt will "interrupt" what you are presently doing. In fact and to the contrary, it is a critical point of design that your program as such should never know that an interrupt has occurred at all because the interrupt has left the operating state of the main routine absolutely unchanged. Interrupts are intended only for events that occur in "computer time"; that need to be attended to within microseconds. By the same token, they have to be dealt with and completed within fractions of a millisecond - if only because other such important events may require attention.
Clearly your concern is a matter of organisation of these "setup" routines. You need an "exit status" defined either as a return status of a function, or a global flag which can be rippled back through each nested function as each tests this status and implements an immediate exit if the status is "reset".
Like the red button on your mobile phone of course.
You just plain can't doit with goto anyway. the label has scope just like a var.
The typical issue you are likely to face is that you may be inside a chain of called functions when the ‘reset’ button is pressed. You need to exit each of those functions, until you are back in the loop() function, where you can reset things.
You may be able to avoid being in a chain of many functions by using a state machine, as Nick suggests. If you can’t easily avoid being inside a chain of functions, here are two possible approaches. [Note that C++ on the Arduino doesn’t support exceptions, otherwise the obvious approach would be to propagate an exception.]
When the reset is requested, set a global ‘resetRequested’ boolean variable, and exit the current function. Everywhere the function is called, immediately after the call you need to check this variable, and if it is set then exit the now-current function. And so on until the calling function is loop(), at which point you check the flag, and if it is set, clear the flag and do the reset.
There is a pair of functions called setjmp and longjmp which can be used to do a “goto” out of nested functions. They are a hangover from C. You would use code like this:
if (setjmp(env) == 0)
// put normal processing code here
// if we get here, then longjmp has been called
// put the code to reset things here
if (...) // if a reset has been requested
longjmp(env); // go to the place where setjmp was called
setjmp/longjmp need to be used with caution. In particular, if you are using dynamic memory allocation (e.g. the String class), then memory leaks may occur.
Using setjmp/longjmp is not a nice solution - and it is never used in the safety-critical applications which are my line of work - but in a non-critical application, may be the easiest way to get the job done. Do not call setjmp or longjmp from inside an ISR.
I agree with dc42 (as usual). You could use what he described, but my preference would be the state machine, simply because then it is easy to go back a step as well as reset.
However if "back to square one" is what is required, and it is hard to do it any other way, then the longjmp is a way out.
Caveat: This is a form of "goto" so it should only be used if there is no neater way of achieving what you want.
Thanks for all the input guys... I'm looking at the overall flow, and see how to reorganize things to make this more straightforward.
I have a bad tendency to get stuck in a rut and try to plow my way through, versus climbing up out of the rut, and look to see why I got there in the first place....
...ever been there?
too much time coding, too little time breathing...