Menu

Operation

DNC
Attachments
CodeBlock.jpg (2149 bytes)
DefsBlock.jpg (2401 bytes)
OpsBlock.jpg (2305 bytes)
SM.png (18256 bytes)

State Machine

This program has been designed to be as easy to use as possible. There are two steps to define and operate a state machine. First, the state machine must be defined. Second, the defined state machine must be operated.

Three blocks of code are required to operate a state machine according to this project.

The state machine code block is found in the files section of this project:
SM diagram
A definition code block is supplied by the user/developer to define the structure of the state machine:
SM diagram
An operations code block is supplied by the user/developer to operate a previously defined state machine:
SM diagram

I will discuss how to define the state machine first, then how to operate the state machine by accessing the state machine code.

Define State Machine

Before a state machine may used, every state in the state machine must be defined: i.e. the name of the state, transitions from this state and associated state function, must be specified as described in detail below. Code in the state machine block processes the definitions to generate a data structure representing the state machine. The decorators described below are coded in the state machine code block. Consequently, the decorator code block must have a access to the state machine code block to operate properly.

State

Generic state definition --

:::python
transitions = (symbol1="newState1", symbol2="newState2", ... symbolN="newStateN")
#
# Define state "stateName"
#
@state("stateName",  **transitions)
def stateFunction(dataIn):

    . . .

    return dataOut

Where:
stateName is a string representing the name of the newly defined state.
stateFunction is a function which is executed when the stateName state is entered.
transitions is a dictionary defining the transitions from this state. The dictionary contains a plurality of entries, each one containing a string key representing a newly received symbol, and a string value representing the new state to transition to when the symbol is received.
dataIn is data of any type provided by the operating code along with a new symbol. This data can have any data structure desired and able to be handled by the state function.
dataOut is data of any type returned by the state function to the operating code by execution of the state function.

Referring again to transitions:
symbol1 is a string representing an expected input symbol.
newState1 is string representing the name of the state to transition to when symbol 1 is received.
symbol2 is a string representing an expected input symbol.
newState2 is string representing the name of the state to transition to when symbol 1 is received.

and so forth to:
symbolN is a string representing an expected input symbol.
newStateN is string representing the name of the state to transition to when symbol 1 is received.

A search of Python documentation will reveal other methods of passing a dictionary of transitions to the state decorator. For example:

:::python
transitions = {"symbol1": "newState1", "symbol2": "newState2", ... "symbolN": "newStateN"}
@state("stateName", **transitions)

or

@state("stateName", symbol1="newState1", symbol2="newState2", ... symbolN="newStateN")

Any such techniques may be used according to your situation and personal style. I like the last one and will use that one in the following discussion.

Initial State

To specify that a state is the initial state, use the decorator @initialState, instead of @state.

:::python
#
# Define initial state "startStateName"
#
@initialState("startStateName",  **transitions)
def startStateFunction(dataIn):

    . . .

    return dataOut

Diagram

It is generally easier to design a state machine using a state diagram. The definition of states, described above, may be easily performed by reference to the diagram.

SM diagram

Diagram's states definition --

:::python
#
# Define state "Start"
#
@initialState('Start', Next='Second', Cancel='End')        # INITIAL STATE
def startFunc(dataIn):

    . . .

    return dataOut


#
# Define state "Second"
#
@state('Second', Next='Multi', Cancel='End')
def secondFunc(dataIn):

    . . .

    return dataOut


#
# Define state "Multi"
#
@state('Multi', Next='Stopped', Cancel='End', To1="Int1")
def multiFunc(dataIn):

    . . .

    return dataOut


#
# Define state "Stopped"
#
@state('Stopped', Next='End', Cancel='End')
def stoppedFunc(dataIn):

    . . .

    return dataOut
#
# Define state "Missing"
#
@state('Missing', Next='End', Cancel='End')
def missingFunc(dataIn):

    . . .

    return dataOut


#
# Define state "Int1"
#
@state('Int1', Rtn='Multi', To2="Int2")
def int1Func(dataIn):

    . . .

    return dataOut


#
# Define state "Int2"
#
@state('Int2', Rtn='Stopped', To1="Int1")
def int2Func(dataIn):

    . . .

    return dataOut

Operate State Machine

In general terms, a state machine operates by supplying it with a series of symbols, with optional data associated with each symbol, and receiving data back from the state machine in response. This repeats until the overall processing is completed. Before this can begin, the state machine must be initialized to be in the initial state.

To initialize:

:::python
dataReturned = start(dataPassedIn)

The data passed in is passed to the start state function. The data returned is returned from the starat state function.

To dispatch a symbol to the state machine:

:::python
dataReturned = dispatch(symbol, associatedData)

The symbol is compared to the symbols in the transitions dictionary associated with the current group. If a matching symbol exists, then the new state associated with that symbol becomes the current state, and the state function for that state is executed with the associated data passe to it. Data returned from execution of the state function for the new state is returned to the calling program. If no matching symbol exists in the transitions, then the symbol is silently ignored.


MongoDB Logo MongoDB