Sketch_Restart()

I building grand plans for my arduino mega, involving sequences of actions depending on inputs from the real world that might talk an indeterminate time to happen.

And remote policy commands via a wireless link.

One of the policy actions I would like to implement is - give up and start again.

void (*Sketch_Restart)(void) = 0x0000;

I think that (based on an amateurs lucky reading of the boot-loader code) and testing on the Arduino Mini that this definition works.

Simple test code..
counts the 'c's that it sees
prints when sent a 'p'
and restarts from the beginning when sent an 'r'

#define GREEN_LED 7    // flickers fast
#define RED_LED 8      // slow flicker
#define YELLOW_LED 9   // more of a flash

void setup()
{
  Serial.begin(9600) ;
  pinMode(GREEN_LED, OUTPUT) ;
  pinMode(RED_LED, OUTPUT) ;
  pinMode(YELLOW_LED, OUTPUT) ;
  digitalWrite(GREEN_LED, 1) ;
  digitalWrite(RED_LED, 1) ;
  digitalWrite(YELLOW_LED, 1) ;
}

void (*Sketch_Restart)(void) = 0x0000;

static int static_variable = 0 ;
static unsigned long counter = 0 ;

void loop()
{
  counter++ ;

  if ((counter % (16u*1024LU)) == 0UL) // every 16k thru the loop
  {
    digitalWrite(GREEN_LED, (counter % (32u*1024UL)) == 0UL) ; // togle green
    if ((counter % (32u*1024UL)) == 0UL) // every 32k times
    {
      digitalWrite(RED_LED, (counter % (64u*1024UL)) == 0UL) ; // toggle red
      if ((counter % (64u*1024UL)) == 0UL) // every 64k times
        digitalWrite(YELLOW_LED, (counter % (128u*1024UL)) == 0UL) ; // toggle yellow
    }
  }
  
  
  if(Serial.available()) // a character is waiting
  {
    switch(Serial.read())
    {
      case 'r':
        Sketch_Restart() ; // call the start of myself:)
        break ; // dosnt get here
        
      case 'c':
        static_variable ++ ; // count my 'c's
        break ;
        
      case 'p':
        Serial.print("static_variable = ") ; 
        Serial.println(static_variable) ; 
        Serial.print("loop counter = ") ; 
        Serial.println(counter) ; 
        break ;
    }
  }
}

I do not know enough to know if this test means that what I want tio happen is happening - or if it is just luck.

I would feel much happier if it was a part of the Arduino API :slight_smile:

Dave

There is a lot of discussion on this forum about this function pointing to 0x0000. It restarts your code but it won't reset all registers and internal counters. If you search for "reset function" (upper right) you find several threads e.g. - http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1235780325

That said, as long as it works for your sketches ...

Thanks for the pointers, I now have read quite a bit more, and perhaps I understand some more.

I understand the comments from others in the past - that a software reset() is not really a good thing to seek out...

But given the sorts of things that I want to ask my poor micro controller to do (tack my model boat, and get the sails on the right side pulling, and head a certain direction, ...)
And that I want that to be done in combinations of interrupt code and other peoples PID code and etc...

I am sure that a fast - start from the very beggining() - method is worth having ;).

All that said, what I understand is required is:

Set all the device registers to the initial states documented in the datasheet

Set the cpu registers to zero

jmp 0

#ifdef simple_reset
void (*sketchRestaRt)(void) = 0x0000; 
#else
#include <avr/io.h>
void sketchRestart(void)
{
  noInterrupts() ; // no interrupts while adjusting register values.
  
  // SET ALL DOCUMENTED REGISTERS TO THEIR POWER ON VALUES.
  
  MCUSR = 0  ; // no reset source
  WDTCSR = 0 ; // no watch dog resets
  EICRA = 0 ; // no external interrupts
  EIMSK = 0 ; // external interrupt mask cleared
  EIFR = 0 ; // external interrupt flag register - no pending interrupts
  PCICR = 0 ; // pin change interrupt control register
  PCIFR = 0 ; // pin change inetrrupt flag register
  PCMSK2 = 0 ; // pin change mask register 2
  PCMSK1 = 0 ; // pin change mask register 1
  PCMSK0 = 0 ; // pin change mask register 0
  
  // port B
  DDRB = 0 ;
  PORTB = 0 ;
  // PINB not defined.
  
  // port C
  DDRC = 0 ;
  PORTC = 0 ;
  // PINC not defined
  
  // port D
  DDRD = 0 ;
  PORTD = 0 ;
  // PIND not defined
  
  // timer prescalers (timer 0 and 1)
  GTCCR = 0 ;
  
  // Timer - 0
  TCCR0A = 0 ;
  TCCR0B = 0 ;
  TCNT0 = 0 ;
  OCR0A = 0 ;
  OCR0B = 0 ;
  TIFR0 = 0 ;
  TIMSK0 = 0 ;
  
  // Timer - 1
  TCCR1A = 0 ;
  TCCR1B = 0 ;
  TCCR1C = 0 ;
  TCNT1 = 0 ; // 16 bit
  OCR1A = 0 ; // 16 bit
  OCR1B = 0 ; // 16 bit
  ICR1 = 0 ; // 16 bit
  TIFR1 = 0 ;
  TIMSK1 = 0 ;
  
  // Timer - 2
  TCCR2A = 0 ;
  TCCR2B = 0 ;
  TCNT2 = 0 ;
  OCR2A = 0 ;
  OCR2B = 0 ;
  TIFR2 = 0 ;
  TIMSK2 = 0 ;
  
  // Assynchronous Status Register (timer 2 stuff)
  ASSR = 0 ;
  
  // SPI
  SPCR = 0 ;
  SPSR = 0 ;
  // SPDR undefined on restart
  
  // usart0
  UDR0 = 0 ;
  UCSR0A = 0 ; // UDRE0 bit is read only, and 1 according the restart normal logic
                        // can not change a read-only bit :(
  UCSR0B = 0 ;
  UCSR0C = _BV(UCSZ01) | _BV(UCSZ00) ; // reset values are these bits.
  UBRR0L = 0 ;
  UBRR0H = 0 ;
  
  // two wire interface
  TWBR = 0 ;
  TWCR = 0 ;
  TWSR = 0 ;
  
  TWDR = 0xff ; // this write might not suceed. Is only writeable when TWI is not shifting a byte.
                // maybe should disable twi as early as possible, so more chance this instruction works.
                // could need to delay for >1 milliSec for byte to be sent.
                // I do not use TWI (yet) so can perhaps ignore this.

                
  TWAR = ~(_BV(TWGCE)) ; // all bits except TWGCE set.
  TWAMR = 0 ;
  
  // analog comparator
  ADCSRB = 0 ;
  ACSR = 0 ;
  DIDR1 = 0 ;
  
  // ADC
  ADMUX = 0 ;
  ADCSRA = 0 ;
  ADCSRB = 0 ;
  DIDR0 = 0 ;
  
 // ADCL = 0 ;  // read only and the output of a conversion, not really a problem if not 0 on restart.
 // ADCH = 0 ;  // read only
 
  // debugWire - not accessible outside debugWire
  // DWDR = 0 ;  // might be prohibited from setting this.
  
  
  // flash access control
  SPMCSR = 0 ;
  
  // clear registers - still to do

  interrupts() ;
  
  asm volatile ("jmp 0") ;
}
#endif

Ok... i haven't cleared the cpu registers yet - and there are IO registers that are read only with
values defined at startup - so sketchRestart() is never going to be a 100% reset,
but all the periperals that I care about are done/ for a 168 or a 368.

It sort of works, except that the output of the first print is corrupted after the reset.

I am guessing that the hardware serial code is assuming some control value has been set in the boot loader.

That will be a problem for tomorrow.

And then the register clear.

And then the same stuff for a Mega 1280.

Maybe I am optimistic... but I think that then we will have a sketchReset() that is fast and reliable :sunglasses:

Dave

Maybe I am optimistic... but I think that then we will have a sketchReset() that is fast and reliable

Well the point that sold me on not having/using a 'softReset' function is that it is usually just a lack of imagination and/or experience at program structure.

When someone can explain why they must have that function and that there is not other way for s/he's program to function without it, then maybe I will stand in that line. Until then, color me meh...

I think I would rather learn how to master better program structure. Learning software skills has been frustrating to me at times, but I do feel I'm making steady progress. Mostly because I stay away from that nasty C++ stuff and just swim in the C part of the pool. :wink:

Lefty

If you really need a reset (and I'm not saying you do), what's wrong with a watchdog?
That's what they are designed for.

(still trying to reconcile 'fast' and 'sailboat' in my head)

AWOl,

Sail boats are slowish.. but it is remote controlled, and possible to capsize, so if i get confused, or the micro controller gets confused, i do want a way back to the beggining.

So I think the watch-dog will go to hardware reset vector - and then wait for a timeout... and then start listening to commands.

Since I will already be in panic mode when i go for the reset, the extra delay is likely to panic me more.

Lefty,

C++ is a nice language. I have spent too many years doing coding. The first 10 years where a purgetory of assembler, fortran 4, pascal and c. Then we got a c++ compiler.

When you deal with something a lot/ like for 10+ years/ you have patterns and methods that make the problems easier to work with.

If you use C++ to represent what you know about the problem space then it frees you to concentrate on the novel parts of the problem. I really like C++ for this reason.

But since I know almost nothing about electronics, or the arduino, or the ATMEGAxx, I am using C++ to write C code.

And asking silly questions.

Dave

The code is better or at least more elaborate..

Lots more comments as I have read more detail about how the USART works in the 328 and the 168.

Clears registers :).

The corruption on the serial port is reduced a bit.

if you send 'ccccccccccccccccccccccccpr' as one string then the last character of the printed data is not properly
flushed through the usart when the reset happens, and the next time i send a 'p' a garbage character is printed in place of the newline.

I think the change that I made with most effect was to comment out UDR0 = 0 ; when I realised that it was a bi-directional register.

I have still not worked out how to drain the transmit path.. i almost think it mioght not be possible

But, it is getting closer I think, and I know some more, and having fun.

Now I have registers cleared, and most of the USART code right (i think) next is to review the other devices.

Regards,
Dave

#define GREEN_LED 7    // flickers fast
#define RED_LED 8      // slow flicker
#define YELLOW_LED 9   // more of a flash

void setup()
{
  Serial.begin(115200) ;
  pinMode(GREEN_LED, OUTPUT) ;
  pinMode(RED_LED, OUTPUT) ;
  pinMode(YELLOW_LED, OUTPUT) ;
  digitalWrite(GREEN_LED, 1) ;
  digitalWrite(RED_LED, 1) ;
  digitalWrite(YELLOW_LED, 1) ;
}
#ifdef simple_reset
void (*sketchRestaRt)(void) = 0x0000;
#else
#include <avr/io.h>
void sketchRestart(void)
{
  noInterrupts() ; // no interrupts while adjusting register values.
  
  // SET ALL DOCUMENTED REGISTERS TO THEIR POWER ON VALUES.
  
  MCUSR = 0  ; // no reset source
  WDTCSR = 0 ; // no watch dog resets
  EICRA = 0 ; // no external interrupts
  EIMSK = 0 ; // external interrupt mask cleared
  EIFR = 0 ; // external interrupt flag register - no pending interrupts
  PCICR = 0 ; // pin change interrupt control register
  PCIFR = 0 ; // pin change interrupt flag register
  PCMSK2 = 0 ; // pin change mask register 2
  PCMSK1 = 0 ; // pin change mask register 1
  PCMSK0 = 0 ; // pin change mask register 0
  
  // port B
  DDRB = 0 ;
  PORTB = 0 ;
  // PINB not defined.
  
  // port C
  DDRC = 0 ;
  PORTC = 0 ;
  // PINC not defined
  
  // port D
  DDRD = 0 ;
  PORTD = 0 ;
  // PIND not defined
  
  // timer prescalers (timer 0 and 1)
  GTCCR = 0 ;
  
  // Timer - 0
  TCCR0A = 0 ;
  TCCR0B = 0 ;
  TCNT0 = 0 ;
  OCR0A = 0 ;
  OCR0B = 0 ;
  TIFR0 = 0 ;
  TIMSK0 = 0 ;
  
  // Timer - 1
  TCCR1A = 0 ;
  TCCR1B = 0 ;
  TCCR1C = 0 ;
  TCNT1 = 0 ; // 16 bit
  OCR1A = 0 ; // 16 bit
  OCR1B = 0 ; // 16 bit
  ICR1 = 0 ; // 16 bit
  TIFR1 = 0 ;
  TIMSK1 = 0 ;
  
  // Timer - 2
  TCCR2A = 0 ;
  TCCR2B = 0 ;
  TCNT2 = 0 ;
  OCR2A = 0 ;
  OCR2B = 0 ;
  TIFR2 = 0 ;
  TIMSK2 = 0 ;
  
  // Assynchronous Status Register (timer 2 stuff)
  ASSR = 0 ;
  
  // SPI
  SPCR = 0 ;
  SPSR = 0 ;
  // SPDR undefined on restart
  
  // usart0
  if ( UCSR0B & (1<<RXEN0)) // if recieve enabled, drain the input buffers
  {
    unsigned char dummy;
    while ( UCSR0A & (1<<RXC0) ) dummy = UDR0; // while data present read from receive queue
  }
  
  if (UCSR0B & (1<<TXEN0)) // if transmit enabled
  {
// Try to to drain the transmit fifo; sometimes we do not succeed, we leave the data
// in the shift register and change the settings, leading to garbage on the line.
// This code is not sure to work, as it is not possible to reliably tell if
//   there is data in the trasmit shift register.
// The bit TXC0 is cleared after a transmit interrupt is sent, and can be cleared by code.
// If the TXC0 bit is clear, it could mean that there is data waiting to be sent or that there isn't.
// If the TXC0 bit is set, there is no data to send.
// The only reliable signal that there is more data to send is the UDRE0 bit which indicates that one and
// a part characters are waiting to be sent.
    if ((UCSR0A & (1<<UDRE0)) == 0) // there is a byte in the transmit fifo
    {
      while ((UCSR0A & (1<<UDRE0)) == 0) // while transmit queue is not empty
        ; // drain the transmit buffer
      while ((UCSR0A & (1<<TXC0)) == 0) // transmit of last character not yet complete
        ; // and wait for the transmit shift buffer to empty
    }
  }
    
// the UDR0 register supplys the data for both input and output side of UART comms..
// UDR0 = 0 ; // would be transmitting a null :( - leads to corruption because we are about to set the speed to 1M Bit/second.
// if I put this back the garbage is much more :)

  UCSR0A = 0 ; // RXC0 bit is clear due to read queue draining above
               // TXC0 bit is cleared by assinment to 0.
               // UDRE0 bit is read only, and 1 according the restart normal logic
               // UDRE0 bit should be 1 if transmit was enabled because of the transmit fifo draining above.
               // FE0 (frame error) is cleared by draining the read queue
               // DOR0 (data over run) is cleared by draining read queue
               // UPE0 (usart parity error) is cleared by draining the read queue
               // U2X0 (double baud rate) is set to zero by assignment of 0
               // MPCM0 (multi-processor communication mode) cleared by to zero by assignment of 0
               
  UCSR0B = 0 ; // no recieve interrupt, no TX complete interrupt, no UDR empty interrupt, reciever disabled, transmitter disabled,
               // ! 9bit chars, 9th bit in =0, 9th bit out=0
  UCSR0C = _BV(UCSZ01) | _BV(UCSZ00) ; // reset values are these bits; // 8 bit characters
                // UMSEL01, UMSEL00 - bits are 0, indiactes Asynchronous USART
                // UPM01, UPM00 - bits are 0, partity disabled.
                // USBS = 0, one stop bit
                // UCSZ01, UCSZ02 - bits are 1, implies 8 bits per character.
                // UCPOL0, bit is 0, asynchronous mode.
                
  UBRR0L = 0 ;  // baud rate is clock divided by 16
  UBRR0H = 0 ;  // 
  
  // two wire interface - more to check
  TWBR = 0 ;
  TWCR = 0 ;
  TWSR = 0 ;
  
  TWDR = 0xff ; // this write might not suceed. Is only writeable when TWI is not shifting a byte.
                // maybe should disable twi as early as possible, so more chance this instruction works.
                
  TWAR = ~(_BV(TWGCE)) ; // all bits except TWGCE set.
  TWAMR = 0 ;
  
  // analog comparator
  ADCSRB = 0 ;
  ACSR = 0 ;
  DIDR1 = 0 ;
  
  // ADC
  ADMUX = 0 ;
  ADCSRA = 0 ;
  ADCSRB = 0 ;
  DIDR0 = 0 ;
  
 // ADCL = 0 ;  // read only
 // ADCH = 0 ;  // read only
 
  // debugWire - not accessible outside debugWire
  // DWDR = 0 ;  // might be prohibited from setting this.
  
  
  // flash access control
  SPMCSR = 0 ;
  

  asm volatile ("clr r0") ;
  asm volatile ("clr r1") ;
  asm volatile ("movw r2, r0") ;
  asm volatile ("movw r4, r0") ;
  asm volatile ("movw r6, r0") ;
  asm volatile ("movw r8, r0") ;
  asm volatile ("movw r10, r0") ;
  asm volatile ("movw r12, r0") ;
  asm volatile ("movw r14, r0") ;
  asm volatile ("movw r16, r0") ;
  asm volatile ("movw r18, r0") ;
  asm volatile ("movw r20, r0") ;
  asm volatile ("movw r22, r0") ;
  asm volatile ("movw r24, r0") ;
  asm volatile ("movw r26, r0") ;
  asm volatile ("movw r28, r0") ;
  asm volatile ("movw r30, r0") ;
  interrupts() ;
  asm volatile ("jmp 0") ;
}
#endif

static int static_variable = 0 ;
static unsigned long counter = 0 ;

void loop()
{
  counter++ ;

  if ((counter % (16u*1024LU)) == 0UL) // every 16k thru the loop
  {
    digitalWrite(GREEN_LED, (counter % (32u*1024UL)) == 0UL) ; // togle green
    if ((counter % (32u*1024UL)) == 0UL) // every 32k times
    {
      digitalWrite(RED_LED, (counter % (64u*1024UL)) == 0UL) ; // toggle red
      if ((counter % (64u*1024UL)) == 0UL) // every 64k times
        digitalWrite(YELLOW_LED, (counter % (128u*1024UL)) == 0UL) ; // toggle yellow
    }
  }
  
  
  if(Serial.available()) // a character is waiting
  {
    switch(Serial.read())
    {
      case 'r':
        sketchRestart() ; // call the start of myself:)
        break ; // dosnt get here
        
      case 'c':
        static_variable ++ ; // count my 'c's
        break ;
        
      case 'p':
        Serial.print("static_variable = ") ; 
        Serial.println(static_variable) ; 
        Serial.print("loop counter = ") ; 
        Serial.println(counter) ; 
        break ;
    }
  }
}

Since I will already be in panic mode when i go for the reset, the extra delay is likely to panic me more.

16 milliseconds is going to panic you more? Will that extra 16 milliseconds make that much of a difference on a sailboat? Would you even be able to tell the difference between zero delay and a 16 millisecond delay?

In my experience, less code = fewer bugs. You're adding quite a bit of code to "reset" the processor. Does your plan include a method for identifying bugs in your reset code? What if your reset code does not work correctly? Will you have a "reset squared" in case your "reset" fails to work?

Thanks for the questions...

I don't see 16ms delay on a reset. When my Arduiono Mini resets it spends a LONNGGGGGG time waiting in the boot loader
Sometimes it feels like 10 seconds.

Since it is easy to plug into a prototype board, the Mini is what I use on the desk, so almost exclusively.

I have always had to time about 2 seconds after starting the download in the IDE to release of the reset switch to get
new software downloaded onto it, but it works :).

A while back I put a new bootloader on the Mini, using the IDE, in the hope that it would be better, with no difference perceived.

Is there some way to avoid this delay that I have missed?

Dave

16ms is the watchdog timeout, the rest of the time after the watchdog RESET is the bootloader.
Once you have proved your software, put it direct into a fresh AVR without a bootloader.
Hopefully by then, you'll have tested your software so well, you won't actually need the watchdog.

Ok,

I see where you are coming from - I can replace the bootloader code, so I shouldn't fuss with the reset.

That is probably the correct low risk approach as my simulated reset is never going to be quite right (as otherwise ATMEL would have a doc on their site saying how to do it).

But I am treating it as a learning exercise, to better understand the processor, while also preserving the ability to bootload the code.

My eventual objective is that I will be able to build quite complex strategies into the top level controller - with no need to have the logic that reverts each path back to a known starting point.

This is an extension of a well known approach in application development - called "Crash only software" http://lwn.net/Articles/191059/ - which states that you know your program will fail, so design for it to fail and recover gracefully, and quickly.

If you get it right (like I hope to) then you are free to actively use the fail & recovery path to simplify your system...

So for example, I will only code the control algorithms to a position that is defined in terms of the current position.

All the commands that request a change to a position determined from the boot up state will be saved in a EEPROM location and executed after restart.

This should reduce the amount of code I need to write quite a bit.

Dave

This is an extension of a well known approach in application development - called "Crash only software" http://lwn.net/Articles/191059/ - which states that you know your program will fail, so design for it to fail and recover gracefully, and quickly.

Which is a rehash of a much older concept called a "watchdog timer".

It's still my opinion that you are trying to solve a problem that does not exist. Just write better/proper structure to begin with, would seem to me to be better all around strategy?

" Who guards the guards?"

Lefty

Hi Coding Badly and Lefty,

(sorry i hit tab in the editor and then return which posted while i was still working on it)

I will try to sketch out the reasoning for the software sketchReset() for you and explain how it is just a bit different to a Watch-Dog-Timer...

First picture a program structure in loop() that implements various tasks in functions, and each task-function breaks its steps into lower level functions..

So there might be a function which called tack() to sail the boat onto the other side of the wind...
that is if the wind is on the left of the boat at the start, it should be on the right at the end - and the boat should move forwards at all times...

Here is a rough (first try at) tack()

void tack()
{
   boolean startTack = currentTack() ;

   while (currentSpeed() < 0 || startTack == currentTack()) // while not moving forwards or not on the new tack
   { // work to fix these issues 

       while (speed() < 0) // sailing backwards
      {
          try_to_sail_forwards() ;  // this is pretty complex in of itself - and will take some time to fix.
                                                // in a real boat can break things by sailing backwards.
      }

      // we are sailing forwards - is a good start :)

      // have to start a tack with some boat speed, because sailing through the wind slows us down - we can end out stopped
      //  head to the wind - 'in irons' is the old term.
      // we will drift backwards with the wind and then need the try_to_sail_forwards() ...


      // we are sailing forwards
      while (currentTack() == startTack) // we are still on the wrong tack
      {
         // work to sail fast enough to tack
           while (currentSpeed() < GOOD_STEERAGE_WAY) // while not going fast enough to turn into the wind and across to the other tack
          { // work to sail faster
              try_to_sail_faster() ;
          }

          while (sailsPulling()) // still under power from wind
          {
              while (currentSpeed() > GOOD_STEERAGE_WAY) // still fast enough to manoeuvre
              {
                 headUpALittle() ; /// steer into the wind  
                 trimSails() ; // adjust the sails so they keep pulling
              }
          }
          // sails not pulling - to close to the wind to sail..
          while (currentTack() == startTack && headingVersusWind() < currentSpeed() * CLUDGE_FACTOR) // not tacked and still moving
          { // we should be able to continue through wind onto other tack
              loosenSails() ; // reduce drag from wind on the boat
              headUpALittle() ; // steer into the wind, not too much or rudder will act like a brake
          }
     // either on the right tack or are too slow
     }
// on the right tack now, but the tack is not complete until you are moving with STEERAGE_WAY
     while (currentSpeed() < GOOD_STEERAGE_WAY) // while not going fast enough 
     { // work to sail faster
          try_to_sail_faster() ;
     }
return ; // on the right tack now.
}

The thing to notice is almost all the commands are relative adjustments to controls or policy...
And that each function trimSails(), as an extreme example, could be as involved as the above.

If every thing is working then the boat should smoothly sail up to close to the wind, let the sails loose and then continue to glide through the wind onto the other tack, and then trim the sails in and sail away on the other tack.

If it goes wrong... then the control software will not know how to move to a better state.

For example, if the wind shifts by 50 degrees, then the boat could be caught head to wind, and just think that the wind has died....

At that point, I by remote control, would send boat the command to do the wake-up and gain control sequence - ie the power on sequence.

I know that there are finite state machine approaches to control software that might allow this stuff to be written differently, with different classes of special cases that are difficult to deal with...

But this is the sort of way I think when I attempt to explain sailing...

So I think the patterns will be quite complex...

// I could wrap each function call with an abort signal propagator - something like

if (!trimSails()) return false ;

// And in the character received interrupt
   if (ch == 0x3) // control-C
      abortRequested = true ; // will be seen in loops

// And the application code where it fails
if (unhandledCaseHappens())
    return false ;

//with checks in every loop like so

if (abortRequested)
   return false ;

but it seems ugly in comparison to

// in the code where required
if (unhandledCaseHappens())
    restartSketch() ;

// in the character received interrupt
   if (ch == 0x3) // control-C
       restartSketch() ;

This is LIKE the Watch Dog Timer of old.. - which is still a good idea where the requirement is to ensure that the code stays on the straight and narrow..

and a bit like cheap software exceptions with exactly one catch() block - the sketch reload point :).

Dave