Sketch_Restart()

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