State Machine Design Guidelines

From IGSTK

Jump to: navigation, search

Contents

Introduction

The safety and robustness of IGSTK as a surgical toolkit requires that each component has a state machines that is properly designed and validated. It is therefore important that we have guidelines for the proper design and validation of our state machines.

Design Patterns

The safety of a state machine results from its ability to validate each input and take the appropriate action.

When you are designing the state machine for an IGSTK component, it is absolutely crital that you ask yourself the following question for each block of code in the component:

 Are all necessary conditions satisfied before this code block is executed?

If there was no state machine, you would probably check all the conditions with a series of "if" statements, and hope that you didn't miss any conditions that you needed to check! In a large, complicated component, it can be difficult to keep track of all the conditions.

The idea behind using a state machine is that you can formalize the process of condition checking. You will define a set of "States" for your component, and whenever your component is in a particular "State", that means that a particular set of conditions are satisfied.

Then, you break your code into a set of "Processing Methods" and enter them into the state transition table. By entering these methods into the state transition table, you have declared that each of these methods will only be called when the object is in a particular state, i.e. these methods will only be called when certain conditions have been satisfied. This means you can get rid of all the "if" statements, because the state machine guarantees that the conditions have been satisfied before your code is executed.

This probably sounds confusing if you haven't designed a state machine before. Studying the following two common state machine patterns should help:

Attempt Pattern: Wait For Action Completion

The "Attempt" pattern in state machines is a classic safety mechanism. It can be very well illustrated by the example of an elevator door control mechanism. Let's look specifically at the case where an elevator door is opening:

  1. Three states are involved: ClosedState, OpeningState, and OpenState.
  2. Two inputs are involved: StartOpeningInput (when someone pushing the open button), and FinishedOpeningInput (when the door senses that it is fully open).
  3. The following rules are in place: The elevator cannot move while the door is opening, and the elevator ignores the "close" button until it is fully open.

...needs a diagram and more discussion...

Parameter Validation Pattern: Check Condition Before Processing

The "Parameter Validation" pattern is a way of validating parameters that are passed to our components. The idea behind a validation scheme is that a single Request method might actually represent multiple possible inputs to the state machine, based on the values of the parameters sent to the method.

As an example, consider the following method:

   RequestSetNeedleInsertionDepth(double z)

What if only positive values of "z" are allowed? Then we our Request method to examine the value of "z", and send one input if the value is negative and another if it is non-negative. The value of "z" determines which input is sent. In fact, a useful way to think of it is that the parameter "z" is converted into a state machine input.

...needs a diagram and more discussion...

Other Information

The following section includes further discussion of design patterns for state machines:

State Machines#Recurring Patterns in State Machine Design

Naming Conventions

In order to make IGSTK more readable, it is necessary for all IGSTK programmers to follow the same conventions when naming the Inputs, States, and Methods associated with the state machines of their components.

The following rules should always be followed. Deviation from these rules is absolutely not allowed, because it is essential that we all follow the same conventions, or else we will have a hard time reading each other's code!

State Names

    1. All state names must end in State. The igstkAddStateMacro() will automatically append 'm_' in front and 'State' behind the parameter
     Example:
     
     igstkAddStateMacro( Ready ); // Add a m_ReadyState
    1. When an object is first created, it should be in a state called InitialState unless there is a strong reason to call its initial state something else.
     Example:
     
     m_StateMachine.SelectInitialState( m_InitialState );
    1. If a state exists where the object has started an attempt to fulfill a request, but has not yet completed the request, that state must start with Attempting.
     Example:
     
     igstkAddStateMacro( AttemptingStartTracking );

InputNames

    1. All input names must end in Input. The igstkAddInputMacro() will automatically append 'm_' in front and 'Input' behind the parameter
     Example:
     
     igstkAddInputMacro( Success ); // Add a m_SuccessInput
    1. If an input leads to an Attempting state, the input must be prefixed with Attempt.
     Example:
     
     igstkAddInputMacro( AttemptConnectToTrackerTool );
    1. If an input is pushed by one particular Request method, then the input should be named after the request method unless there is a strong reason to name the input something else.
     Example:
     
     RequestConnectToTrackerTool() should push AttemptConnectToTrackerToolInput

Method Names

    1. All interface methods that push inputs to the state machine must be prefixed by Request. This indicates to the caller that the method is not a "sure thing". It is just a request! Etiquette is very important.
     For example:
 
     void SpatialObject::RequestAttachToTrackerTool( const TrackerTool * trackerTool );
    1. All methods that are called by the state machine must be suffixed by Processing
     For example:
 
     void SpatialObject::AttachToTrackerToolProcessing();
    1. For each class, there is a special method that is meant to be called whenever no action is to be performed during a state transition. This special method must always be called NoProcessing. NOTE: igstkAddTransitionMacro() will automatically append 'm_' in front and 'State' or 'Input' behind the parameters.
     For example:
     
     void PulseGenerator::NoProcessing()
     {
     }
     
     igstkAddTransitionMacro( WaitingEventReturn, EventReturn, Pulsing, NoProcessing );
    1. If any processing method that is called by the state machine contains actions that can produce more than one possible outcome, that method must be prefixed by Attempt. The Attempt methods are how the state machine deals with Requests internally: a Request causes an Attempt, and the Attempt method can generate different Inputs to describe the result of the Attempt.
     For example:
     
     void SpatialObject::AttemptAttachToTrackerToolProcessing():
    1. If a particular processing method is specifically meant to be called after an Attempt method has a successful outcome, the method name should end with SuccessProcessing. If a processing method is meant to be called specifically after an Attempt fails, that method name should end with FailureProcessing. If an Attempt has multiple successful outcomes or multiple failure outcomes then Success or Failure can be replaced with a more descriptive name.
     For example:
     
     void SpatialObject::AttachToTrackerToolSuccessProcessing();
     
     void SpatialObject::AttachToTrackerToolFailureProcessing();
     
     void SerialCommunication::WriteTimeoutProcessing();
    1. If an input produces positive actions from more than one state, the method name should contain both the input name and the state name and should end in StateProcessing:
     For Example:
     
     void SpatialObject::AttemptAttachToTrackerToolFromInitialStateProcessing();
     
     void SpatialObject::AttemptAttachToTrackerToolFromNonTrackedStateProcessing();
     
     [just an example... SpatialObject cannot attach to TrackerTool in InitialState!]
    1. If a processing method is meant to be called as a result of an input/state combination that is not valid, the method name should include Invalid:
     For example:
     
     void SpatialObject::InvalidRequestProcessing();
<p>

Personal tools
TOOLBOX
LANGUAGES